tap口創建流程
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地址。
創建接口的操作是neturonn乾的,不歸dhcp_agent,dhcp_agent只不過是rpc遠程調用
在/neuturon/agent/dhcp/agent.py
class DhcpPluginApi(object):
"""Agent side of the dhcp rpc API.
This class implements the client side of an rpc interface. The server side
of this interface can be found in
neutron.api.rpc.handlers.dhcp_rpc.DhcpRpcCallback. For more information
about changing rpc interfaces, see doc/source/devref/rpc_api.rst.
API version history:
1.0 - Initial version.
1.1 - Added get_active_networks_info, create_dhcp_port,
and update_dhcp_port methods.
1.5 - Added dhcp_ready_on_ports
"""
def __init__(self, topic, host):
self.host = host
target = oslo_messaging.Target(
topic=topic,
namespace=n_const.RPC_NAMESPACE_DHCP_PLUGIN,
version='1.0')
self.client = n_rpc.get_client(target)
@property
def context(self):
# TODO(kevinbenton): the context should really be passed in to each of
# these methods so a call can be tracked all of the way through the
# system but that will require a larger refactor to pass the context
# everywhere. We just generate a new one here on each call so requests
# can be independently tracked server side.
return context.get_admin_context_without_session()
def get_active_networks_info(self):
"""Make a remote process call to retrieve all network info."""
cctxt = self.client.prepare(version='1.1')
networks = cctxt.call(self.context, 'get_active_networks_info',
host=self.host)
return [dhcp.NetModel(n) for n in networks]
def get_network_info(self, network_id):
"""Make a remote process call to retrieve network info."""
cctxt = self.client.prepare()
network = cctxt.call(self.context, 'get_network_info',
network_id=network_id, host=self.host)
if network:
return dhcp.NetModel(network)
def create_dhcp_port(self, port):
"""Make a remote process call to create the dhcp port."""
cctxt = self.client.prepare(version='1.1')
port = cctxt.call(self.context, 'create_dhcp_port',
port=port, host=self.host)
if port:
return dhcp.DictModel(port)
def update_dhcp_port(self, port_id, port):
"""Make a remote process call to update the dhcp port."""
cctxt = self.client.prepare(version='1.1')
port = cctxt.call(self.context, 'update_dhcp_port',
port_id=port_id, port=port, host=self.host)
if port:
return dhcp.DictModel(port)
def release_dhcp_port(self, network_id, device_id):
"""Make a remote process call to release the dhcp port."""
cctxt = self.client.prepare()
return cctxt.call(self.context, 'release_dhcp_port',
network_id=network_id, device_id=device_id,
host=self.host)
def dhcp_ready_on_ports(self, port_ids):
"""Notify the server that DHCP is configured for the port."""
cctxt = self.client.prepare(version='1.5')
return cctxt.call(self.context, 'dhcp_ready_on_ports',
port_ids=port_ids)
這邊又看到一個人寫的流程很好:
neutron-dhcp-agent收到neutron server創建網絡的通知和neutron-dhcp-agent主動承載一個網絡的操作基本上是一樣的,如下
dhcp-agent.ini中dhcp_driver設置爲 dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
- 檢查網絡中是否有enable dhcp的subnet, 有則會調用dhcp_driver的enable操作
- Dnsmasq.enable()
2.1 如果當前存在Dnsmasq的進程,則重啓, 沒有則繼續操作
2.2. 調用DeviceManager的setup方法,
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. 調用driver的init_l3(),初始化dhcp namespace中的路由規則, 其中包括subnet中的默認網關以及metadata相關的路由。
2.2.5 調用dhcp_driver的spawn_process()
2.2.5.1 在創建Dnsmasq服務之前需要初始化它的配置文件, 包括三個文件(hosts_file, addn_hosts_file, opts_file)
hosts_file: 記錄mac, hostname, ip的映射關係
addn_hosts_file: 記錄ip, 長hostname,短hostname的映射關係
opts_file: 記錄默認路由以及dns server
2.2.5.2 創建Dnsmasq進程。
這樣創建一個網絡,包括subnet的過程基本結束了。
原文鏈接:https://blog.csdn.net/allenson1/article/details/54602007
就是在\neutron\agent\linux\dhcp.py中class DhcpLocalProcess(DhcpBase):類裏的device_manager.setup(self.network)
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()
def setup_dhcp_port(self, network):
"""Create/update DHCP port for the host if needed and return port."""
# The ID that the DHCP port will have (or already has).
device_id = self.get_device_id(network)
# Get the set of DHCP-enabled local subnets on this network.
dhcp_subnets = {subnet.id: subnet for subnet in network.subnets
if subnet.enable_dhcp}
# There are 3 cases: either the DHCP port already exists (but
# might need to be updated for a changed set of subnets); or
# some other code has already prepared a 'reserved' DHCP port,
# and we just need to adopt that; or we need to create a new
# DHCP port. Try each of those in turn until we have a DHCP
# port.
for setup_method in (self._setup_existing_dhcp_port,
self._setup_reserved_dhcp_port,
self._setup_new_dhcp_port):
dhcp_port = setup_method(network, device_id, dhcp_subnets)
if dhcp_port:
break
else:
raise exceptions.Conflict()
def _setup_new_dhcp_port(self, network, device_id, dhcp_subnets):
"""Create and set up new DHCP port for the specified network."""
LOG.debug('DHCP port %(device_id)s on network %(network_id)s'
' does not yet exist. Creating new one.',
{'device_id': device_id, 'network_id': network.id})
# Make a list of the subnets that need a unique IP address for
# this DHCP port.
if self.driver.use_gateway_ips:
unique_ip_subnets = []
else:
unique_ip_subnets = [dict(subnet_id=s) for s in dhcp_subnets]
port_dict = dict(
name='',
admin_state_up=True,
device_id=device_id,
network_id=network.id,
tenant_id=network.tenant_id,
fixed_ips=unique_ip_subnets)
return self.plugin.create_dhcp_port({'port': port_dict})
self.plugin.create_dhcp_port({‘port’: port_dict}) 爲遠程rpc調用
然後找到配置 文件的位置
def spawn_process(self):
"""Spawn the process, if it's not spawned already."""
# we only need to generate the lease file the first time dnsmasq starts
# rather than on every reload since dnsmasq will keep the file current
self._output_init_lease_file()
self._spawn_or_reload_process(reload_with_HUP=False)
def _spawn_or_reload_process(self, reload_with_HUP):
"""Spawns or reloads a Dnsmasq process for the network.
When reload_with_HUP is True, dnsmasq receives a HUP signal,
or it's reloaded if the process is not running.
"""
self._output_config_files()
pm = self._get_process_manager(
cmd_callback=self._build_cmdline_callback)
pm.enable(reload_cfg=reload_with_HUP)
self.process_monitor.register(uuid=self.network.id,
service_name=DNSMASQ_SERVICE_NAME,
monitored_process=pm)