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)