查看 /neutron/agent/dhcp/agent.py
中 class DhcpAgent
找到
self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
self.dhcp_driver_cls是Dnsmasq的类实例。
self.dhcp_driver_cls=importutils.import_class(self.conf.dhcp_driver)中的dhcp_driver也为/etc/neutron/dhcp_agent.ini配置文件中参数。
DhcpAgent类_init_函数如下(创建实例部分)
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.dhcp_ready_ports = set()
self.conf = conf or cfg.CONF
self.cache = NetworkCache()
self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, self.conf.host)
# create dhcp dir to store dhcp info
dhcp_dir: Union[bytes, str] = os.path.dirname("/%s/dhcp/" % self.conf.state_path)
fileutils.ensure_tree(dhcp_dir, mode=0o755)
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')
DhcpAgent通过self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)注册了Dnsmasq这个Driver,并在需要的时候调用driver的相应接口。注意这个时候只是注册了一个调用Dnsmasq的driver并没有启动dnsmasq这个进程哦。
agent先同步网络的状态再决定是否创建dnsmasq进程,以下是同步状态的函数(/dhcp/agent.py),
特别注意 for network in active_networks:这段代码,openstack的操作是,有一个子网就起一个dnsmasq进程,
spawn(self.safe_configure_dhcp_for_network, network)就类似linux的fork起进程的操作。spawn走 safe_configure_dhcp_for_network 要看
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('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('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('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('Synchronizing state complete')
当创建网络的时候,发现子网里面需要开启DHCP server,则调用self.call_driver(‘enable’, network)。剩下的就是驱动做的事情了我找不到了。
def safe_configure_dhcp_for_network(self, network):
try:
network_id = network.get('id')
LOG.info('Starting network %s dhcp configuration', network_id)
self.configure_dhcp_for_network(network)
LOG.info('Finished network %s dhcp configuration', network_id)
except (exceptions.NetworkNotFound, RuntimeError):
LOG.warning('Network %s may have been deleted and '
'its resources may have already been disposed.',
network.id)
def configure_dhcp_for_network(self, network):
if not network.admin_state_up:
return
for subnet in network.subnets:
if subnet.enable_dhcp:
if self.call_driver('enable', network):
self.update_isolated_metadata_proxy(network)
self.cache.put(network)
# After enabling dhcp for network, mark all existing
# ports as ready. So that the status of ports which are
# created before enabling dhcp can be updated.
self.dhcp_ready_ports |= {p.id for p in network.ports}
break
def call_driver(self, action, network, **action_kwargs):
"""Invoke an action on a DHCP driver instance."""
LOG.debug('Calling driver for network: %(net)s action: %(action)s',
{'net': network.id, 'action': action})
try:
# the Driver expects something that is duck typed similar to
# the base models.
driver = self.dhcp_driver_cls(self.conf,
network,
self._process_monitor,
self.dhcp_version,
self.plugin_rpc)
getattr(driver, action)(**action_kwargs)
return True
except exceptions.Conflict:
# No need to resync here, the agent will receive the event related
# to a status update for the network
LOG.debug('Unable to %(action)s dhcp for %(net_id)s: there '
'is a conflict with its current state; please '
'check that the network and/or its subnet(s) '
'still exist.', {'net_id': network.id, 'action': action})
except exceptions.SubnetMismatchForPort as e:
# FIXME(kevinbenton): get rid of this once bug/1627480 is fixed
LOG.debug("Error configuring DHCP port, scheduling resync: %s", e)
self.schedule_resync(e, network.id)
except Exception as e:
if getattr(e, 'exc_type', '') != 'IpAddressGenerationFailure':
# Don't resync if port could not be created because of an IP
# allocation failure. When the subnet is updated with a new
# allocation pool or a port is deleted to free up an IP, this
# will automatically be retried on the notification
self.schedule_resync(e, network.id)
if (isinstance(e, oslo_messaging.RemoteError)
and e.exc_type == 'NetworkNotFound'
or isinstance(e, exceptions.NetworkNotFound)):
LOG.debug("Network %s has been deleted.", network.id)
else:
LOG.exception('Unable to %(action)s dhcp for %(net_id)s.',
{'net_id': network.id, 'action': action})
现在找到了self.call_driver根据网络和端口的变化,会调用/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():
fileutils.ensure_tree(self.network_conf_dir, mode=0o755)
interface_name = self.device_manager.setup(self.network)
self.interface_name = interface_name
self.spawn_process()
具体的C 在这个函数 def _build_cmdline_callback 也是/neutron/linux/dhcp.py下