作者:闫兴安
1.4 代码流程分析
1.4.1 dhcp port如何进行bind_port
plugin中,在创建port时会进行bind_port。所谓bind是指端口id、主机名、网络属性进行绑定。
其中网络属性包括:网络ID、网络类型、物理网络名称、网络segment-id。
bind_port的过程:
1) 按序遍历所有mech_driver,挨个进行bind_port。
2) 如果某个mech_driver报异常,记log,然后继续进行下一个mech driver的bind。
3) 如果某个mech_driver没有进行绑定,继续进行下一个mech driver的bind。
4) 只要有一个mech_driver bind成功,就返回。(ovs driver不支持多层bind)
5) 如果所有的mech_driver都绑定失败,记vif_type为binding_failed。
我们的环境中mech_driver只有openvswitch,所以来看下ovs driver的binding:
1) 遍历所有agent,如果是down的,不进行绑定,记Log;如果是active的,执行下面步骤。
2) 检查agent的上报过来的配置。包括:网络类型是否在agent的配置文件中配置;如果是flat和vlan类型的网络,还检查物理网络名称是否在agent的配置文件中配置;
3) 如果上述检查不通过,不进行绑定;如果检查通过,进行绑定。
4) 只要有一个agent绑定成功,就返回,表示ovs driver绑定成功。
5) 如果所有的agent都没有进行绑定,就会出现binding_failed。
1.4.2 dhcp-agent与plugin的同步
dhcp-agent主动同步过程:
1) 启动时,首先从namespace名字中获取网络信息,记录到cache(内存)中。后续从plugin获取的所有信息都记录在cache里。之后进行同步时依据的就是这个cache。
2) 可以同步指定的网络列表,或者同步所有的网络。
3) 开始同步,打印INFO Synchronizing state。
4) 从plugin中获取全部网络,和cache对比,删除多余的本地网络的dhcp,使能本地缺失的网络的dhcp。使能动作在geen pool里进行,默认4个thread。
5) 等待步骤4全部完成,打印INFO Synchronizing state complete。
plugin主动下发配置:
1) ml2 plugin通过mech driver发送网络、子网、端口事件给dhcp-agent。
2) 包括创建、修改、删除网络、子网、端口。
3) dhcp-agent收到事件后,立即进行相应处理,见下面cache的处理过程。
同步时间:
1) 第一次report state之后立即进行同步。然后起个定时器,当有reason时进行同步。reason为需要进行同步的网络ID,或者全部网络。周期同步时间默认为5秒。
2) agent状态刚刚从down变为active的时候,标记reason为全部网络,等待周期同步。
3) 当启动dnsmasq进程失败时,标记reason为失败的网络。
4) 同步时,删除dnsmasq进程失败时,标记reason为失败的网络。
5) agent的状态变化时,同步全部网络。
dnsmasq driver包括如下几种接口:
1) enable,生成配置文件、创建namespace和端口、启动dnsmaq进程。如果dnsmasq进程存在,参考下面的reload。
2) disable,关闭dnsmasq进程、删除namespace和端口、删除配置文件。
3) reload,重新生成lease文件,然后给dnsmasq进程发送HUP信号,进程会重新加载配置文件。如果dnsmasq进程不存在,会启动进程。
4) restart,相当于先执行disable,然后执行enable,此过程不删除namespace和端口。
从上面的同步过程可以看出,同步的关键在于cache里network信息的维护:
1) 启动时,首先从namespace名字中获取网络信息,记录到cache(内存)中。
2) plugin发来创建网络消息时,执行driver的enable接口。如果dnsmasq driver返回成功,将网络记录到cache中。如果不成功,标记该网络重新进行同步,同时driver内部会进行回退处理,保证没有资源残留。
3) plugin发来删除网络消息时,执行driver的disable接口。如果dnsmasqdriver返回成功,将网络从cache中删除。如果不成功,标记该网络重新进行同步,同时driver内部会进行回退处理,保证没有资源残留。
4) plugin发来更新网络消息时,如果admin_state_up修改为up,参考步骤2,否则参考步骤3。
5) plugin发来创建、删除、更新子网消息时,根据前后子网内容的变化,执行disable、restart、reload。这里,disable和restart执行成功才记录cache。reload时是无条件记录cache。
6) plugin发来创建、更新端口消息时,如果端口是本地的IP,并且端口IP发生变化时,执行restart,否则reload。restart和reload无条件记录cache。
7) plugin发来删除端口消息时,执行reload。无条件清除cache。
这里存在的问题:
有些地方没有判断driver是否成功,所以可能存在cache与底层不一致的情况。
1.4.3 tap口如何创建
先来看下interface driver:
dhcp agent先通过plugin创建dhcp port,plugin返回Port详情,包括port ID,mac地址,IP地址等信息。
然后通过interface driver先ovs-vsctl add-port 创建一个internal的tap口,然后加入到br-int中。然后创建namespace,将tap加入namespace,在tap口上配置IP地址。
从下面的debug日志可以看出dhcp agent创建底层端口的过程。
1.4.4 dhcp-agent日志分析
1) Unable to sync network state
当出现mysql失联等原因,导致plugin无法处理同步请求时报此错误。
2) Unable to enable dhcp for XXX
需要结合traceback分析。
agent请求某个网络的详情,plugin因某种原因(比如mysql失联),未能正确返回数据时。
当执行底层命令失败时也会出现此错误。
3) Unable to disable dhcp for XXX
同enable。
4) [req-XXX ] Network XXX infocall failed.
当agent向plugin请求某个网络时出现异常,也需要结合traceback分析。
1.1.5 测试plugin是否主动调度网络
将dhcp-agent中self.periodic_resync()代码注掉,重启dhcp-agent。
创建网络,看能否创建dhcp-port。
可以创建。
这说明创建网络时的调度并不依赖于周期同步。
1.4.6 网络DHCP调度
首先,网络调度都是由Agent触发的,只要agent请求某个网络,或者全部网络时,就会触发网络的调度。调度动作是针对某个agent的,会找出该agent可以承载的网络。
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。
查找某个网络“正在承载此网络的agent”:
1) 在agent与网络的绑定这个table中,根据网络网络ID进行查找。
2) 排除状态是down的agent。但是包含刚刚启动的agent。
从上面的调度可以看出,只要有dhcp agent状态down了,网络重新调度时就会排除此agent。
如果agent状态又up了,又会网络调度到此agent。
1.4.7 是否可以修改每个网络的agent数目?
从上面的DHCP调度算法可以看出,只要开启了autoschedule,承载网络的数目就一定是agents_per_network的数目。而且网络所在的Agent无法手动指定(即使手动指定,agent down/up一切换,就会重新调度)。
参数 |
默认值 |
用途 |
network_auto_schedule |
True |
自动为网络分配agent。 |