删除子网的时候DHCP的变化

我们通常知道的答案是当删除子网的时候会会回调dhcp-agent的subnet_delete_end函数。然后调用driver的restart来重新加载dnsmasq进程,但今天我想说一点细节的东西。

##细节一:什么时候把一个网络分发到一个agent上去,

当第一个DHCP port创建后,会做2个件事情

  • 为这个network schedule到一个agent上去
  • 给所有个agent发送消息比如port_create_end

所以一个有意思的流程是,当一个subnet创建后,并不一定会通知dhcp_agent,因为要考虑这时候dhcp-port有没有创建,如果没有创建的话,说明连dhcp-agent也没有呢,自然不需要notify
那么什么时候创建dhcp-port呢?当一个subnet通过router-interface-add添加一个port的时候,就会触发dhcp-port的创建。然后schedule agent,
然后后续的subnet都会通知这些dhcp agents了

<% codeblock %>
def add_router_interface(self, context, router_id, interface_info):
add_by_port, add_by_sub = self._validate_interface_info(interface_info)
device_owner = self._get_device_owner(context, router_id)

if add_by_port:
    port = self._add_interface_by_port(
        context, router_id, interface_info['port_id'], device_owner)
elif add_by_sub:
    port = self._add_interface_by_subnet(
        context, router_id, interface_info['subnet_id'], device_owner)
    super(L3_NAT_db_mixin, self).send_dhcp_notification(
        context, {'port': port}, 'port.create.end') 

<% endcodeblock %>

所以会发送一个创建port的指令,然后会schedule一个agent来负责这个network,然后agent会做如下操作:

  • 拉subnet数据到agent
  • 创建dhcp_port(实际上是从neutron server获得分配给本dhcp port的信息,比如ip mac啥的,实际还是在本地创建)

之后再创建subnet就会notify 这个agent了。

##细节二:DHCP Port上的IP什么时候删除的

当port/subnet有更新的时候,会走restart流程,然后

  • 拉新的network数据
  • 重建dhcp_port,一般调用update_dhcp_port,然后重新设置ip网关之类的
    <% codeblock %>
    def setup(self, network, reuse_existing=False):

    """Create and initialize a device for network's DHCP on this host."""
    port = self.setup_dhcp_port(network)
    interface_name = self.get_interface_name(network, port)
    
    if ip_lib.device_exists(interface_name,
                            self.root_helper,
                            network.namespace):
        if not reuse_existing:
            raise exceptions.PreexistingDeviceFailure(
                dev_name=interface_name)
    
        LOG.debug(_('Reusing existing device: %s.'), interface_name)
    else:
        self.driver.plug(network.id,
                         port.id,
                         interface_name,
                         port.mac_address,
                         namespace=network.namespace)
    
    ip_cidrs = []
    for fixed_ip in port.fixed_ips:
        subnet = fixed_ip.subnet
        net = netaddr.IPNetwork(subnet.cidr)
        ip_cidr = '%s/%s' % (fixed_ip.ip_address, net.prefixlen)
        ip_cidrs.append(ip_cidr)
    
    if (self.conf.enable_isolated_metadata and
        self.conf.use_namespaces):
        ip_cidrs.append(METADATA_DEFAULT_CIDR)
    
    self.driver.init_l3(interface_name, ip_cidrs,
                        namespace=network.namespace)
    
    # ensure that the dhcp interface is first in the list
    if network.namespace is None:
        device = ip_lib.IPDevice(interface_name,
                                 self.root_helper)
        device.route.pullup_route(interface_name)
    
    if self.conf.use_namespaces:
        self._set_default_route(network, port=port)
    return interface_name
    

<% endcodeblock %>

##细节二:在Neutron Server上,那个子网的IP什么时候删除的