zoukankan      html  css  js  c++  java
  • openstack Neutron分析(3)—— neutron-dhcp-agent源码分析

    1.neutron dhcp3个主要部件分别为什么?
    2.dhcp模块包含哪些内容?
    3.Dnsmasq配置文件是如何创建和更新的?
    4.DHCP agent的信息存放在neutron数据库的哪个表中?

    扩展: neutron-dhcp-agent在neutron的作用是什么?




    一.概述

    neutron dhcp为租户网络提供DHCP服务,即IP地址动态分配,另外还会提供metadata请求服务。
    3个主要的部件:
    DHCP agent scheduler:负责DHCP agent与network的调度
    DHCP agent:为租户网络提供DHCP的功能,提供metadata request服务。
    DHCP driver:即dnsmasq,用于管理DHCP server。


    二.REST API

    neutron dhcp提供2类REST API接口,这两类API都是extension API。



    一种是 Agent Management Extension API:

    <ignore_js_op> 



    另一种是agent调度:

    <ignore_js_op> 



    三.总体架构


    根据整个dhcp处理的流程,dhcp模块主要由Neutron api、core plugin(如linux bridge plugin,ovs plugin等)、dhcp agent scheduler、dhcp agent、dhcp driver(dnsmasq)构成。
    架构图如下:

    <ignore_js_op> 
    对应架构图中数字,有以下几个接口:

    1.network/subnet/port的操作
    2.agent management/agent scheduler的操作
    3.network/subnet/port操作会发送rpc请求到dhcp agent。
    4.agentscheduler db发送rpc请求到dhcp agent。
    5.dhcp agent通过DhcpPluginApi发送rpc请求到core plugin,操作相应的数据库。
    6.dhcp agent调用dhcp driver进行dhcp相关操作。
    四.代码分析
    neutron-dhcp-agent的入口为neutron.agent.dhcp_agent:main,跟l3-agent的启动方式是类似的,都是以Service启动;Manager类为DhcpAgentWithStateReport,汇报DHCPAgent的状态。
    1. def main():
    2.     register_options()
    3.     common_config.init(sys.argv[1:])
    4.     config.setup_logging(cfg.CONF)
    5.     server = neutron_service.Service.create(
    6.         binary='neutron-dhcp-agent',
    7.         topic=topics.DHCP_AGENT,
    8.         report_interval=cfg.CONF.AGENT.report_interval,
    9.         manager='neutron.agent.dhcp_agent.DhcpAgentWithStateReport')
    10.     service.launch(server).wait()
    复制代码

    DhcpAgentWithStateReport继承自DhcpAgent,用于汇报DHCPAgent的状态
    1.     if report_interval:
    2.             self.heartbeat = loopingcall.FixedIntervalLoopingCall(
    3.                 self._report_state)
    4.             self.heartbeat.start(interval=report_interval)
    复制代码
    _report_state就是从self.cache中取出当前状态,然后构造一个report_state的message发到q-plugin topic的消息队列上。


    下面看下DhcpAgent初始化过程:

    1. def __init__(self, host=None):
    2.         super(DhcpAgent, self).__init__(host=host)
    3.         self.needs_resync_reasons = []
    4.         self.conf = cfg.CONF
    5.         # Agent cache of the current network state
    6.         self.cache = NetworkCache()
    7.         self.root_helper = config.get_root_helper(self.conf)
    8.         # dhcp_driver currently is neutron.agent.linux.dhcp.Dnsmasq
    9.         self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
    10.         ctx = context.get_admin_context_without_session()
    11.         # init plugin rpc
    12.         self.plugin_rpc = DhcpPluginApi(topics.PLUGIN,  # topic is q-plugin,提供DHCP相关的创建、查询、更新、删除接口
    13.                                         ctx, self.conf.use_namespaces)
    14.         # create dhcp dir to store dhcp info: /var/lib/neutron/dhcp/
    15.         # these files are used for Dnsmasq
    16.         dhcp_dir = os.path.dirname("/%s/dhcp/" % self.conf.state_path)
    17.         if not os.path.isdir(dhcp_dir):
    18.             os.makedirs(dhcp_dir, 0o755)
    19.         self.dhcp_version = self.dhcp_driver_cls.check_version()
    20.         # query existing_dhcp_networks from driver and then save them into self.cache
    21.         self._populate_networks_cache()
    复制代码

    DhcpPluginApi创建了topic为q-plugin的处理方法,dhcp-agent外部可以通过DhcpAgentNotifyAPI来调用这些接口:
    1. class DhcpAgentNotifyAPI(n_rpc.RpcProxy):
    2.     """API for plugin to notify DHCP agent."""
    3.     BASE_RPC_API_VERSION = '1.0'
    4.     # It seems dhcp agent does not support bulk operation
    5.     VALID_RESOURCES = ['network', 'subnet', 'port']
    6.     VALID_METHOD_NAMES = ['network.create.end',
    7.                           'network.update.end',
    8.                           'network.delete.end',
    9.                           'subnet.create.end',
    10.                           'subnet.update.end',
    11.                           'subnet.delete.end',
    12.                           'port.create.end',
    13.                           'port.update.end',
    14.                           'port.delete.end']
    复制代码

    neutron.agent.linux.dhcp.Dnsmasq

    DhcpAgent通过self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)注册了Dnsmasq这个Driver,并在需要的时候调用driver的相应接口:
    1. def call_driver(self, action, network, **action_kwargs):
    2.         """Invoke an action on a DHCP driver instance."""
    3.         LOG.debug(_('Calling driver for network: %(net)s action: %(action)s'),
    4.                   {'net': network.id, 'action': action})
    5.         try:
    6.             # the Driver expects something that is duck typed similar to
    7.             # the base models.
    8.             driver = self.dhcp_driver_cls(self.conf,
    9.                                           network,
    10.                                           self.root_helper,
    11.                                           self.dhcp_version,
    12.                                           self.plugin_rpc)
    13.             getattr(driver, action)(**action_kwargs)
    14.             return True
    复制代码

    Dnsmasq会通过/var/lib/neutron/dhcp/目录下的配置文件启动dnsmasq进程,在DHCP更新的时候,更新这些配置文件并reload配置。
    1. dnsmasq --no-hosts --no-resolv --strict-order  
    2. --bind-interfaces --interface=tap746570b9-2b --except-interface=lo  
    3. --pid-file=/var/lib/quantum/dhcp/3e16cd2f-c693-49b4-91a7-2a65912ec152/pid  
    4. --dhcp-hostsfile=/var/lib/quantum/dhcp/3e16cd2f-c693-49b4-91a7-2a65912ec152/host  
    5. --dhcp-optsfile=/var/lib/quantum/dhcp/3e16cd2f-c693-49b4-91a7-2a65912ec152/opts  
    6. --dhcp-script=/usr/bin/quantum-dhcp-agent-dnsmasq-lease-update --leasefile-ro  
    7. --dhcp-range=set:tag0,12.0.0.192,static,120s  
    8. --conf-file= --domain=openstacklocal 
    9. --bind-interfaces --interface=tap746570b9-2b 
    10. 主要选项:
    11. --except-interface=lo 使多个dnsmasq实例可以同时运行在同一台主机上并监听不同的interface
    12. --dhcp-hostsfile=/var/lib/quantum/dhcp/3e16cd2f-c693-49b4-91a7-2a65912ec152/host 读取IP与虚拟机的静态映射关系,该文件改变后dnsmasq会自动重新加载,不需要重启
    13. --dhcp-optsfile=/var/lib/quantum/dhcp/3e16cd2f-c693-49b4-91a7-2a65912ec152/opts  指定DNS服务器地址等选项
    14. --dhcp-script=/usr/bin/quantum-dhcp-agent-dnsmasq-lease-update --leasefile-ro  lease信息更新与通知
    15. --dhcp-range=set:tag0,12.0.0.192,static,120s  重点在于static参数,该参数限制dnsmasq只能为dhcp-hostsfile包含的主机提供DHCP服务
    复制代码
    既然Dnsmasq是根据/var/lib/neutron/dhcp/目录下的配置文件启动的,那么这些配置文件是如何创建和更新的呢?
    (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中
    1. #Controller
    2. notifier_method = self._resource + '.create.end'
    3. notifier_method = self._resource + '.delete.end'
    4. notifier_method = self._resource + '.update.end'
    复制代码
    可以看到针对每种resource(network, subnet, port),都会有相应的消息发出。dhcp agent根据这些消息来决定何时重新加载dnsmasp配置文件。


    dhcp agent scheduler

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

    如何调度dhcp agent

    调度算法通过network_scheduler_driver配置,默认是neutron.scheduler.dhcp_agent_scheduler.ChanceScheduler
    class ChanceScheduler(object):
        """Allocate a DHCP agent for a network in a random way.
        More sophisticated scheduler (similar to filter scheduler in nova?)
        can be introduced later.
        """
    可以看出,这个实现采用了随机分配算法。

    如何调用dhcp agent scheduler

    通过neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.py中
    def notify(self, context, data, method_name): 发送消息时,会调用
    self._notify_agents,有代码
                schedule_required = method == 'port_create_end'
                if schedule_required:
                    agents = self._schedule_network(admin_ctx, network, agents)

    可以看到当系统中有新的port创建后,会调用dhcp agent scheduler分配dhcp agent。


    dhcp服务的启动

    1. def after_start(self):
    2.         self.run()
    3.         LOG.info(_("DHCP agent started"))
    4.     def run(self):
    5.         """Activate the DHCP agent."""
    6.         # 根据系统中的网络配置,启动dhcp服务器进程(dnsmasq)。
    7.         # sync_state()在dhcp agent启动后运行一次。
    8.         self.sync_state()
    9.         # 周期性调用sync_state()
    10.         # dhcp agent会缓存一些网路的信息,通过该任务和neutron同步网络信息,更新本地缓存。
    11.         self.periodic_resync()
    复制代码
    neutron的各种插件实现(core plugin or service plugin)都继承于db包下的对象,这些object实现了对相应资源数据模型的操作。



    五.类图

    <ignore_js_op> 



    六.数据库
    DHCP agent的信息会存放在neutron数据库的agents表中:
    1. mysql> desc agents;
    2. +---------------------+---------------+------+-----+---------+-------+
    3. | Field               | Type          | Null | Key | Default | Extra |
    4. +---------------------+---------------+------+-----+---------+-------+
    5. | id                  | varchar(36)   | NO   | PRI | NULL    |       |
    6. | agent_type          | varchar(255)  | NO   |     | NULL    |       |
    7. | binary              | varchar(255)  | NO   |     | NULL    |       |
    8. | topic               | varchar(255)  | NO   |     | NULL    |       |
    9. | host                | varchar(255)  | NO   |     | NULL    |       |
    10. | admin_state_up      | tinyint(1)    | NO   |     | NULL    |       |
    11. | created_at          | datetime      | NO   |     | NULL    |       |
    12. | started_at          | datetime      | NO   |     | NULL    |       |
    13. | heartbeat_timestamp | datetime      | NO   |     | NULL    |       |
    14. | description         | varchar(255)  | YES  |     | NULL    |       |
    15. | configurations      | varchar(4095) | NO   |     | NULL    |       |
    16. +---------------------+---------------+------+-----+---------+-------+
    复制代码

    DHCP agent和network绑定关系存储在networkdhcpagentbindings中:
    1. mysql> desc networkdhcpagentbindings;
    2. +---------------+-------------+------+-----+---------+-------+
    3. | Field         | Type        | Null | Key | Default | Extra |
    4. +---------------+-------------+------+-----+---------+-------+
    5. | network_id    | varchar(36) | NO   | PRI | NULL    |       |
    6. | dhcp_agent_id | varchar(36) | NO   | PRI | NULL    |       |
    7. +---------------+-------------+------+-----+---------+-------+
    复制代码
    agents和networkdhcpagentbindings通过dhcp agent id建立引用关系。
    网络,子网和端口信息分别存储在数据库的networks,subnets和ports表中。dhcp agent需要获取这些信息生成dnsmasq的配置信息,并将这些信息存储在/var/lib/neutron/dhcp/目录下。 当neutron-server有需要添加/修改/删除dhcp相关配置时,会将消息发送到队列dhcp_agent.hostname或dhcp_agent_fanout_id,dhcp agent收到消息后进行相应dhcp的配置。



    相关文章

    openstack Neutron分析(2)—— neutron-l3-agent


    openstack Neutron分析(4)—— neutron-l3-agent中的iptables

    openstack Neutron分析(5)-- neutron openvswitch agent


    Openstack之neutron入门


    Openstack之neutron入门二 


    Openstack之neutron入门三 

    http://www.aboutyun.com/thread-9533-1-1.html

  • 相关阅读:
    https原理以及golang基本实现
    关于Goroutine与Channel
    Golang中log与fmt区别
    liteide使用中的注意点
    Golang中的error类型
    关于linux中的目录配置标准以及文件基本信息
    Godep的基本使用
    Golang基本类型整理
    ssh使用技巧
    看完让你彻底搞懂Websocket原理
  • 原文地址:https://www.cnblogs.com/allcloud/p/5504064.html
Copyright © 2011-2022 走看看