dhcp-agent分析

发布时间:2017-12-18 | 杂志分类:计算机
免费制作
更多内容

dhcp-agent分析

分析dhcp-agent一、简介三、配置使用 3.1 配置 3.2 命令行操作四、源码分析 4.1、 介绍 4.2、DHCP agent启动 4.3、DhcpAgentWithStateReport类-状态汇报 4.4、处理RPC API 4.4.1 向neutron-server获取资源详情 4.4.2 通知neutron-server port ready 4.4.3 dhcp agent通过rpc接口管理dhcp端口(创建删除更新),比如创建port: 4.5 dhcp agent schedule 4.5.1 如何调度dhcp agent 4.5.2 如何选择一个agent 4.6 DHCP Driver-Dnsmasq 4.7 Dnsmasq log五、常用场景分析 5.1 ml2资源创建 5.1.1 流程图 5.1.2 代码... [收起]
[展开]
dhcp-agent分析
粉丝: {{bookData.followerCount}}
文本内容
第1页

分析dhcp-agent

一、简介

三、配置使用

3.1 配置

3.2 命令行操作

四、源码分析

4.1、 介绍

4.2、DHCP agent启动

4.3、DhcpAgentWithStateReport类-状态汇报

4.4、处理RPC API

4.4.1 向neutron-server获取资源详情

4.4.2 通知neutron-server port ready

4.4.3 dhcp agent通过rpc接口管理dhcp端口(创建删除更新),比如创建port:

4.5 dhcp agent schedule

4.5.1 如何调度dhcp agent

4.5.2 如何选择一个agent

4.6 DHCP Driver-Dnsmasq

4.7 Dnsmasq log

五、常用场景分析

5.1 ml2资源创建

5.1.1 流程图

5.1.2 代码分析

5.2 VM创建过程

5.3 VM启动

分析dhcp-agent

一、简介

DHCP-Agent为租户网络提供DHCP服务,即IP地址动态分配,另外还会提供metadata请求服务。

三个主要部件:

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

DHCP agent:为租户网络提供DHCP功能,提供metadata request服务

DHCP driver:dnsmasq,DHCP server

三、配置使用

3.1 配置

DHCP agent 的配置文件位于 \/etc\/neutron\/dhcp_agent.ini。

第2页

--dhcp_driver

使用 dnsmasq 实现 DHCP。

interface_driver

使用 OVS连接 DHCP namespace interface。

3.2 命令行操作

1、先创建网络,执行命令:

其中NETNAME替换为想创建的网络名。是否支持外部网络以及网络类型自行选择。

例如:

neutron net-create public --router:external --provider:physical_network external --provider:network_type

vlan

2、然后为其创建子网,执行命令:

neutron subnet-create NAME 192.168.10.0\/24 --name SUBNETNAME --allocation-pool

start=192.168.10.100,end=192.168.10.120 --enable-dhcp

在创建子网时需DHCP服务时,输入enable-dhcp指令。在创建完子网后,可以通过neutron subnet-list 指令查看

子网信息。

在创建子网成功后会创建一个DHCP的进程dnsmasq

找到对应的192.168.10.0\/24的DHCP进程的命名空间,然后找到对应的监听接口。

第3页

(4)DHCP进程参数 不会读取在 目录下的\/etc\/hosts hostnames

--no-hosts Dnsmasq为在同一台机器上运行多个实例提供DHCP服务

--bind-interfaces

--interface 在指定的 interface 上监听 DHCP 请求

--dhcp-hostsfile

--addn-hosts DHCP host文件的位置

--dhcp-optsfile

--dhcp-range addn-hosts的位置,存放了host的ip地址

--dhcp-lease-max

--domain opts文件的位置,存放了dns、router信息

开启了DHCP服务的子网范围信息

Dnsmasq的最大连接数量,预防dos攻击

指定的dhcp和dns的服务域

(5)在dhcp的目录下的文件

包含6项信息 监听端口的host ip

Addn_hosts

Host 包括host ip 和mac地址

Interface 监听端口的名称

Leases 租赁时间

Opts Option配置项包括router和dns-server信息

Pid dnsmasq进程ID

第4页

四、源码分析

、4.1 介绍

分析分为三个部分,首先会分析DHCP Agent的启动过程,然后分析其状态汇报,再对创建子网时对DHCP进行RPC

调用的代码分析、最后将DHCP具体的管理维护过程。

、 启动4.2 DHCP agent

4.2.1、流程交互图

第5页

4.2.2、具体代码分析

跟其他服务启动一样,在Neutron目录下的setup.cfg文件找到DHCP agent的入口函数在

Neutron\/cmd\/eventlet\/agent\/dhcp中的main函数。

第6页

进入Neutron\/cmd\/eventlet\/agent\/dhcp找到main函数如下

实际上是从dhcp_agent调用的main函数,到\/neutron\/agent\/dhcp_agent.py文件中找到main方法

处理如下:

1. register_options会去读取和注册相关配置,包括dhcp agent和meta的,比如interface_driver,

dhcp_driver,report_interval,

2. 创建一个neutron service,绑定的主题是DHCP_AGENT,默认驱动是Dnsmasq,默认的管理器是

DhcpAgentWithStateReport类.report_interval提供报告服务状态的周期,默认为30秒。

第7页

3. 启动这个service。launch_service方法会为传进来的每个service分配一个绿色线程,且绿色线程启动时,将

会去执行self.run_service方法,且将service和self.done作为参数传给run_service方法去执行。目前,新建的

绿色线程只是标记为可调度,并不会被立即调度执行,只有当主线程执行到gt.wait()时,这个绿色线程才有机

会被调度去执行run_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、初始化本地dhcp已有network

 def _populate_networks_cache(self):   

\"\"\"Populate the networks cache when the DHCP‐agent starts.\"\"\" 

  try: 

  existing_networks = self.dhcp_driver_cls.existing_dhcp_networks( 

  self.conf 

  ) 

  for net_id in existing_networks: 

  net = dhcp.NetModel({\"id\": net_id, \"subnets\": [], \"ports\": []}) 

  self.cache.put(net) 

  except NotImplementedError: 

  # just go ahead with an empty networks cache 

  LOG.debug(\"The '%s' DHCP‐driver does not support retrieving of a \" 

  \"list of existing networks\", 

  self.conf.dhcp_driver)

实际读取目录\/var\/lib\/neutron\/dhcp\/中类id目录,写入内存

第8页

2、neutron-server同步本地的dhcp状态,该方法在启动后运行一次。

#\/neutron\/agent\/dhcp\/agent.py:DhcpAgent

def init_host(self): 

    self.sync_state() 

     

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() 

            # we notify all ports in case some were created while the agent 

            # was down 

            self.dhcp_ready_ports |= set(self.cache.get_port_ids(only_nets)) 

            LOG.info(_LI('Synchronizing state complete'))

2.1 获取\/var\/lib\/neutron\/dhcp\/中类id目录的dhcp networks:known_network_ids =

set(self.cache.get_network_ids())

2.2 发送rpc消息给neutron-server获取数据库网络信息:active_networks=

self.plugin_rpc.get_active_networks_info()

2.3将2.1和2.2数据进行比较

第9页

2.3.1 如果本地存在而neutron-server上本地查不到的network,用disable_dhcp_helper函数从

self.cache进行移除

1)停metadata proxy进程

2)停dnsmasq进程,删除namespace和port,删除相关文件目录

2.3.2 如果neutron-server查到的本地network,重新加载dhcp配置,前提是network中至少有一个subnet

enable dhcp .具体分析参照

3、孵化绿色线程,主要作用是判断报告的时间如果比设置的间隔长就会报warning。如果比设置的间隔短就会

等待。这样就周期性的执行report_state。

4、启动定时任务:最后会调用manager类(dhcpAgentWithStateReport)的after_start方法。

    def after_start(self): 

        self.run() 

        LOG.info(_LI(\"DHCP agent started\")) 

         

    def run(self): 

        \"\"\"Activate the DHCP agent.\"\"\" 

        self.periodic_resync() 

        self.start_ready_ports_loop()

启动定时任务,定时和neutron-server同步本地dhcp状态,在进程启动同步、定时同步、rpc调用等过程中,

出现异常时,会将失败的network加入的self.needs_resync_reasons,定时任务定时检查

self.needs_resync_reasons,如果不为空,则和neutron-server同步流程(和启动进程同步过程类似,只是

启动进程之前需要将之前的进程:kill -9 pid,删除配置文件),默认间隔为6秒

启动定时任务,定时上报新增ready port,进程启动同步、定时同步、rpc调用,这个过程中处理的port都会

加入到self.dhcp_ready_ports,定时任务会定时将这部分数据上报,间隔0.1秒

、 类 状态汇报4.3 DhcpAgentWithStateReport -

文件中找到DhcpAgengtWithStateReport类。首先继承了DhcpAgent的方法,并进行初始化。接着生成了

state_rpc对象,主要是向Plugin发送RPC请求。在agent_state里面包含了DHCP Agent的服务状态。接着定义了定

时任务,报告DHCP的服务状态。具体来看FixedIntervalLoopingCall和_report_state。

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

第10页

class DhcpAgentWithStateReport(DhcpAgent): 

    def __init__(self, host=None, conf=None): 

        super(DhcpAgentWithStateReport, self).__init__(host=host, conf=conf) 

        self.state_rpc = agent_rpc.PluginReportStateAPI(topics.REPORTS) 

        self.agent_state = { 

            'binary': 'neutron‐dhcp‐agent', 

            'host': host, 

            'availability_zone': self.conf.AGENT.availability_zone, 

            'topic': topics.DHCP_AGENT, 

            'configurations': { 

                'notifies_port_ready': True, 

                'dhcp_driver': self.conf.dhcp_driver, 

                'dhcp_lease_duration': self.conf.dhcp_lease_duration, 

                'log_agent_heartbeats': self.conf.AGENT.log_agent_heartbeats}, 

            'start_flag': True, 

            'agent_type': constants.AGENT_TYPE_DHCP} 

        report_interval = self.conf.AGENT.report_interval 

        if report_interval: 

            self.heartbeat = loopingcall.FixedIntervalLoopingCall( 

                self._report_state) 

            self.heartbeat.start(interval=report_interval)

其中_report_state()方法主要代码为:

def _report_state(self): 

    try: 

        self.agent_state.get('configurations').update( 

            self.cache.get_state()) 

        ctx = context.get_admin_context_without_session() 

        agent_status = self.state_rpc.report_state( 

            ctx, self.agent_state, True) 

        if agent_status == n_const.AGENT_REVIVED: 

            LOG.info(_LI(\"Agent has just been revived. \" 

                         \"Scheduling full sync\")) 

            self.schedule_resync(\"Agent has just been revived\") 

    except AttributeError: 

        # This means the server does not support report_state 

        LOG.warning(_LW(\"Neutron server does not support state report. \" 

                        \"State report for this agent will be disabled.\")) 

        self.heartbeat.stop() 

        self.run() 

        return 

    except Exception: 

        LOG.exception(_LE(\"Failed reporting state!\")) 

        return 

    if self.agent_state.pop('start_flag', None): 

        self.run()

处理如下:

1. 从DHCP目录获取更新agent_state词典的configuration信息(网络、子网、port数量)

2. 发送rpc消息给neutron-server报告agent状态;

第11页

3. 如果agent status为revived,则调用方法重新开始同步;

4. 删除agent_state的start_flag后,调用父类的run方法。

、处理4.4 RPC API

neutron-server提供接口,供dhcp agent通过rpc调用,主要有三类功能:

1. DHCP agent从neutron-server获取资源详情

2. DHCP agent通知neutron-server port ready

3. DHCP agent向neutron-server定时报告自己的状态

向 获取资源详情4.4.1 neutron-server

以获取网络资源为例

通知4.4.2 neutron-server port ready

1. DHCP-agent向neutron-server发送PRC 消息,配置完成

2. neutron-server收到消息后,调用neutron.api.rpc.handlers.dhcp_rpc:DhcpRpcCallback类的

dhcp_ready_on_ports()方法删除之前在 ProvisioningBlock表中添加的dhcp记录

第12页

:4.4.3 dhcp agent通过rpc接口管理dhcp端口(创建删除更新),比如创建

port

4.5 dhcp agent schedule

通过dhcp agent scheduler,系统中可以部署多个dhcp agent:

1)增加可用性(HA, high availability),避免单点失败(SOF, single point of failure)

2)增加性能,多个dhcp agent可以安装在多台机器上,同时服务。

如何调度4.5.1 dhcp agent

network scheduler的类型(和router的scheduler类型):

1. ChangeScheduler: 随机分配

2. WeightScheduler: 选择network数量最少的一个agent

调度算法通过network_scheduler_driver配置,默认是

neutron.scheduler.dhcp_agent_scheduler.WeightScheduler,在\/neutron\/db\/agentschedule.py文件注

册。

第13页

可以看出,这个实现采用了权重分配算法。

如何调用dhcp agent scheduler

在neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.py中的notify方法

def notify(self, context, data, method_name): 发送消息时,会调用

self._notify_agents,有代码

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

4.5.2 如何选择一个agent

在neutron\/scheduler\/dhcp_agent_schedule.py的auto_schedule_networks方法

auto_schedule网络调度算法:

1) 首先找到该主机上承载的状态为admin_up的dhcp-agent(只有一个)。

2) 然后遍历所有的网络,执行3-6

3) 对于每个网络,找到正在承载此网络的agent列表。

4) 如果“正在承载此网络的agent”数目与agents_per_network一致,说明该网络已经成功被完全调度,跳过该网

络。否则继续。

5) 判断当前agent是否在“正在承成此网络的agent”里面,如果是,说明该网络被自己调度过了,跳过该网络。否

则继续。

6) 将当前agent与该网络进行绑定。

7) 最终返回该agent新绑定的网络列表。

简单描述就是:网络等待被调度,agent按照先来后到的顺序领取网络,一个网络可以被领指定次数,如果领了网

络的agent失联了,将网络分给其他agent。

4.6 DHCP Driver-Dnsmasq

Dnsmasq 是被 Neutron 用来提供 DHCP 和 DNS 服务的一个开源程序。它提供 DNS 缓存和 DHCP 服务功

能。作为域名解析服务器(DNS),dnsmasq可以通过缓存 DNS 请求来提高对访问过的网址的连接速度。作为DHCP

服务器,dnsmasq 可以为局域网电脑提供内网ip地址和路由。DNS和DHCP两个功能可以同时或分别单独实现。

dnsmasq轻量且易配置,适用于主机较少的网络。

第14页

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

DhcpAgent通过self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)注册了Dnsmasq这个

Driver,并在需要的时候调用driver的相应接口:

Dnsmasq会通过\/var\/lib\/neutron\/dhcp\/目录下的配置文件启动dnsmasq进程,在DHCP更新的时候,更新这些配

置文件并reload配置。

第15页

dnsmasq ‐‐no‐hosts ‐‐no‐resolv ‐‐strict‐order  

‐‐except‐interface=lo  

‐‐pid‐file=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/pid  

‐‐dhcp‐hostsfile=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/host  

‐‐addn‐hosts=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/addn_hosts  

‐‐dhcp‐optsfile=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/opts  

‐‐dhcp‐leasefile=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/leases  

‐‐dhcp‐match=set:ipxe,175  

‐‐bind‐interfaces ‐‐interface=tapb4b26bef‐35  

‐‐dhcp‐range=set:tag0,192.168.7.0,static,86400s  

‐‐dhcp‐option‐force=option:mtu,1450  

‐‐dhcp‐lease‐max=256  

‐‐conf‐file= ‐‐domain=openstacklocal 

 

主要选项: 

‐‐except‐interface=lo 使多个dnsmasq实例可以同时运行在同一台主机上并监听不同的interface 

‐‐dhcp‐hostsfile=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/host 读取IP与虚拟机的静

态映射关系,该文件改变后dnsmasq会自动重新加载,不需要重启 

‐‐dhcp‐optsfile=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/opts  指定DNS服务器地址

等选项 

‐‐dhcp‐leasefile=\/var\/lib\/neutron\/dhcp\/818a6563‐f8dc‐418a‐bbad‐251cba997238\/leases  虚拟机dhcp客户

端列表 

‐‐dhcp‐range=set:tag0,192.168.7.0,static,86400s  重点在于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会根据新网络配置重新生

成配置文件。

第16页

def reload_allocations(self): 

    \"\"\"Rebuild the dnsmasq config and signal the dnsmasq to reload.\"\"\" 

 

    # If all subnets turn off dhcp, kill the process. 

    if not self._enable_dhcp(): 

        self.disable() 

        LOG.debug('Killing dnsmasq for network since all subnets have ' 

                  'turned off DHCP: %s', self.network.id) 

        return 

    if not self.interface_name: 

        # we land here if above has been called and we receive port 

        # delete notifications for the network 

        LOG.debug('Agent does not have an interface on this network ' 

                  'anymore, skipping reload: %s', self.network.id) 

        return 

 

    self._release_unused_leases() 

    self._spawn_or_reload_process(reload_with_HUP=True) 

    LOG.debug('Reloading allocations for network: %s', self.network.id) 

    self.device_manager.update(self.network, self.interface_name)

如果该网络禁用DHCP,就kill掉dnsmasq进程,删除命名空间和dhcp port,删除网络配置目录

释放无用的dhcp,命令:dhcp_release tap-xxx ip mac

重新加载dnsmasq进程,和启动新的dnsmasq进程类似,之不过使用命令:kill -HUP pid重新加载配置

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中

#Controllernotifier_method = self.resource + '.create.end'notifier_method = self.resource +

'.delete.end'notifier_method = self._resource + '.update.end'

可以看到针对每种resource(network, subnet, port),都会有相应的消息发出。dhcp agent根据这些消息来决定何

时重新加载dnsmasp配置文件。

4.7 Dnsmasq log

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

以便调试:

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

log‐facility = \/var\/log\/neutron\/dnsmasq.log 

log‐dhcp 

dnsmasq_config_file = \/etc\/neutron\/dnsmasq.conf 

sudo service neutron‐dhcp‐agent restart 

第17页

五、常用场景分析

5.1 ml2资源创建

当用户创建、更新port等操作,neutron-server发送rpc通知消息到dhcp agent,以create_networkt为类。当

用户创建创建网络后,ml2 plugin完成,就会给DHCP agent发送network_create消息通知。

5.1.1 流程图

5.1.2 代码分析

DhcpAgentNotifyAPI实例初始化时注册相关资源相关事件的回调函数,以port、subnet、network为例。

DHCP agent收到network_create后调用neutron.类同名的network_create_end()方法进行配置

@_wait_if_syncing 

def network_create_end(self, context, payload): 

    \"\"\"Handle the network.create.end notification event.\"\"\" 

    network_id = payload['network']['id'] 

    with _net_lock(network_id): 

        self.enable_dhcp_helper(network_id)

然后调用enable_dhcp_helper()方法,如果数据库中该网络存在,则调用configure_dhcp_for_network()

第18页

1. 判断网络的的admin_state_up是否打开,如果没有打开,则直接返回。

2. 调用dhcp driver拉起dnsmasq,在call_driver函数中,将创建neutron.agent.linux.dhcp.Dnsmasq对象,且

调用该类的enable函数。

代码位置:\/neutron\/agent\/linux\/dhcp.py:DhcpLocalProcess

2.1 如果当前存在Dnsmasq的进程,则重启, 没有则继续操作

2.2 调用DeviceManager的setup方法

class DhcpAgentNotifyAPI(n_rpc.RpcProxy):

第19页

    def setup(self, network): 

        \"\"\"Create and initialize a device for network's DHCP on this host.\"\"\" 

        try: 

            port = self.setup_dhcp_port(network) 

        except Exception: 

            with excutils.save_and_reraise_exception(): 

                # clear everything out so we don't leave dangling interfaces 

                # if setup never succeeds in the future. 

                self._cleanup_stale_devices(network, dhcp_port=None) 

        self._update_dhcp_port(network, port) 

        interface_name = self.get_interface_name(network, port) 

 

        if ip_lib.ensure_device_is_ready(interface_name, 

                                         namespace=network.namespace): 

            LOG.debug('Reusing existing device: %s.', interface_name) 

        else: 

            try: 

                self.plug(network, port, interface_name) 

            except Exception: 

                with excutils.save_and_reraise_exception(): 

                    LOG.exception(_LE('Unable to plug DHCP port for ' 

                                      'network %s. Releasing port.'), 

                                  network.id) 

                    self.plugin.release_dhcp_port(network.id, port.device_id) 

 

            self.fill_dhcp_udp_checksums(namespace=network.namespace) 

        ip_cidrs = [] 

        for fixed_ip in port.fixed_ips: 

            subnet = fixed_ip.subnet 

            if not ipv6_utils.is_auto_address_subnet(subnet): 

                net = netaddr.IPNetwork(subnet.cidr) 

                ip_cidr = '%s\/%s' % (fixed_ip.ip_address, net.prefixlen) 

                ip_cidrs.append(ip_cidr) 

 

        if self.driver.use_gateway_ips: 

            # For each DHCP‐enabled subnet, add that subnet's gateway 

            # IP address to the Linux device for the DHCP port. 

            for subnet in network.subnets: 

                if not subnet.enable_dhcp: 

                    continue 

                gateway = subnet.gateway_ip 

                if gateway: 

                    net = netaddr.IPNetwork(subnet.cidr) 

                    ip_cidrs.append('%s\/%s' % (gateway, net.prefixlen)) 

 

        if self.conf.force_metadata or self.conf.enable_isolated_metadata: 

            ip_cidrs.append(METADATA_DEFAULT_CIDR) 

 

        self.driver.init_l3(interface_name, ip_cidrs, 

                            namespace=network.namespace) 

 

        self._set_default_route(network, interface_name) 

        self._cleanup_stale_devices(network, port) 

第20页

 

        return interface_name

2.2.1. setup_dhcp_port() 如果有dhcp_port,则返回,没有则创建, 根据port里面的device_id选项来区分这

个port是否属于这个agent的dhcp port

2.2.2. 判断port的interface名字是否存在(如:tape613727f-c3 ),如果不存在则会创建这个interface, 调

用driver的plug(这个方法中会创建namespace,创建设备(创建的过程需要openvswitch agent配合,在下面介

绍),并将设备绑定到br-int上)

2.2.3. fill_dhcp_udp_checksum(),在dhcp namespace中创建udp checksum规则?, 如: -A

neutron-dhcp-age-POSTROUTING -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill

2.2.4 如果配置了enable_isolated_metadata配置项,则添加metadata的默认服务IP:169.254.169.254

2.2.5. 调用driver的init_l3(),在命名空间内配置dhcp服务IP和metadata的IP

初始化dhcp namespace中的路由规则, 其中包括subnet中的默认网关以及metadata相关的路由。

2.3 调用dhcp_driver的spawn_process()

2.3.1 输出租约文件leases,内容:时间戳、port mac、port ip

2.3.2 在创建Dnsmasq服务之前需要初始化它的配置文件, 包括三个文件(hosts_file, addn_hosts_file,

opts_file)

hosts_file: 记录mac, hostname, ip的映射关系

addn_hosts_file: 记录ip, 长hostname,短hostname的映射关系

opts_file: 记录默认路由以及dns server

2.3.3 初始化并启动dnsmasq进程,注册dnsmasq进程到process monitor:

第21页

3. 启动或kill掉metadata proxy服务, 如果配置了enable_isolated_metadata项,则在DHCP 网络命名空间中启

动了监听 80 端口的 neutron-ns-metadata-proxy 服务。

def update_isolated_metadata_proxy(self, network): 

    \"\"\"Spawn or kill metadata proxy. 

 

    According to return from driver class, spawn or kill the metadata 

    proxy process. Spawn an existing metadata proxy or kill a nonexistent 

    metadata proxy will just silently return. 

    \"\"\" 

    should_enable_metadata = self.dhcp_driver_cls.should_enable_metadata( 

        self.conf, network) 

    if should_enable_metadata: 

        self.enable_isolated_metadata_proxy(network) 

    else: 

        self.disable_isolated_metadata_proxy(network)

4. 更新network到内存

5. network ports加入self.dhcp_ready_ports

5.2 VM创建过程

Nova-compute 在创建虚机时,需要 Neutron 所做的主要事情之一就是分配一个 MAC 和 一个或者多个固定

IP 地址,该过程从 Nova-compute 向 Neutron 申请 Port 开始:

REQ: curl -i http:\/\/controller:9696\/v2.0\/ports.json -X POST -H \"X-Auth-Token: ...=\" -H \"User-Agent: python-

neutronclient\" -d '{\"port\": {\"binding:host_id\": \"compute1\", \"admin_state_up\": true, \"network_id\": \"0a4cd030-

d951-401a-8202-937b788bea43\", \"tenant_id\": \"43f66bb82e684bbe9eb9ef6892bd7fd6\", \"device_owner\":

\"compute:nova\", \"security_groups\": [\"8c0dc337-0a6d-4ad7-94bf-a400ee32b2ac\"], \"device_id\": \"8671c14e-

9ee4-4338-bcc5-8a5f0ea6e1d5\"}}'

Controller 节点上的 Neutron Server 接到该请求后,会开始下面的过程:

第22页

步骤 2 ~ 6:Neutron Server 生成 MAC 和 IP。 其中 MAC 是由任意数组成的;Fixed IP 是从保存在数据库中的管理

员配置的网络和地址数据生成的。

步骤 7 ~ 10: 调用 L3 Agent 和 OVS 执行一些操作。

步骤 12 ~ 14:通过 AMQP 的 cast 消息给 Neutron 节点上的 DHCP Agent,告诉它 Port 创建结束以及新分配的

Port 的数据。

步骤 13:返回Port 给 nova-compute,数据示例如下:

{\"port\": {\"status\": \"DOWN\", \"binding:host_id\": \"compute1\", \"allowed_address_pairs\": [], \"extra_dhcp_opts\": [],

\"device_owner\": \"compute:nova\", \"binding:profile\": {}, \"fixed_ips\": [{\"subnet_id\": \"5598bdf9-2de4-4a4e-9054-

2070102e0f1f\", \"ip_address\": \"10.0.0.132\"}], \"id\": \"a9ab8ebf-a0b4-4599-867c-95518f069a10\",

\"security_groups\": [\"8c0dc337-0a6d-4ad7-94bf-a400ee32b2ac\"], \"device_id\": \"8671c14e-9ee4-4338-bcc5-

8a5f0ea6e1d5\", \"name\": \"\", \"admin_state_up\": true, \"network_id\": \"0a4cd030-d951-401a-8202-

937b788bea43\", \"tenant_id\": \"43f66bb82e684bbe9eb9ef6892bd7fd6\", \"binding:vif_details\": {\"port_filter\":

true, \"ovs_hybrid_plug\": true}, \"binding:vnic_type\": \"normal\", \"binding:vif_type\": \"ovs\", \"mac_address\":

\"fa:16:3e:f2:e0:23\"}

步骤 15:Neturon 节点上的 DHCP Agent 根据接收到的 Port 创建完成通知,重新生成 Dnsmasq 的 hosts 文件,

然后让 Dnsmasq 重新加载该文件。

该 hosts 文件的示例如下:

[root@Eduhby02 ~]# cat \/var\/lib\/neutron\/dhcp\/5475f453-5ede-4d6a-9e7c-3daa8755f512\/host

fa:16:3e:c8:55:34,host-192-168-1-3.openstacklocal,192.168.1.3

fa:16:3e:d4:63:74,host-192-168-1-2.openstacklocal,192.168.1.2

fa:16:3e:37:77:95,host-192-168-1-12.openstacklocal,192.168.1.12

Nova 拿到 Port 的数据后,会写入虚机的 libvirt.xml 文件。

启动5.3 VM

经过以上步骤,Dnsmasq 准备好相应虚机的IP 申请请求了,它:准备好了 host 文件,里面有每个虚机的

MAC 地址 和 IP 对照表;绑定了 interface,可以收到请求;启动好了进程,可以为指定的 subnet 服务。

第23页

获取 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,整个过程结束。

Dnsmasq会把这个过程如实的记录在文件\/var\/log\/message里:

Aug  7 19:40:01 Eduhby02 dnsmasq[51905]: read \/var\/lib\/neutron\/dhcp\/5475f453‐5ede‐4d6a‐9e7c‐

3daa8755f512\/addn_hosts ‐ 3 addresses       #读取更新后的文件 

Aug  7 19:40:01 Eduhby02 dnsmasq‐dhcp[51905]: read \/var\/lib\/neutron\/dhcp\/5475f453‐5ede‐4d6a‐9e7c‐

3daa8755f512\/host 

Aug  7 19:40:01 Eduhby02 dnsmasq‐dhcp[51905]: read \/var\/lib\/neutron\/dhcp\/5475f453‐5ede‐4d6a‐9e7c‐

3daa8755f512\/opts 

Aug  7 19:40:20 Eduhby02 dnsmasq‐dhcp[51905]: DHCPDISCOVER(tap0a9fa89c‐d6) fa:16:3e:37:77:95 

Aug  7 19:40:20 Eduhby02 dnsmasq‐dhcp[51905]: DHCPOFFER(tap0a9fa89c‐d6) 192.168.1.12 

fa:16:3e:37:77:95 

Aug  7 19:40:20 Eduhby02 dnsmasq‐dhcp[51905]: DHCPREQUEST(tap0a9fa89c‐d6) 192.168.1.12 

fa:16:3e:37:77:95 

Aug  7 19:40:20 Eduhby02 dnsmasq‐dhcp[51905]: DHCPACK(tap0a9fa89c‐d6) 192.168.1.12 

fa:16:3e:37:77:95 host‐192‐168‐1‐12 

云展网——上百万用户在此分享了PDF文档。上传您的PDF转换为3D翻页电子书,自动生成链接和二维码(独立电子书),支持分享到微信及网站!
收藏
转发
下载
免费制作
其他案例
更多案例
免费制作
x
{{item.desc}}
下载
{{item.title}}
{{toast}}