由于笔者水平实在有限,本文只是依据源码对port的创建流程作简单分析,如有问题,欢迎指出;
路径:neutron.plugins.ml2.plugin.py
首先从create方法着手:
@utils.transaction_guard
@db_api.retry_if_session_inactive()
def create_port(self, context, port):
self._before_create_port(context, port)
result, mech_context = self._create_port_db(context, port)
return self._after_create_port(context, result, mech_context)
此函数分为三步,首先进入第一个函数查看:
def _before_create_port(self, context, port):
attrs = port[port_def.RESOURCE_NAME]
if not attrs.get('status'):
attrs['status'] = const.PORT_STATUS_DOWN
registry.notify(resources.PORT, events.BEFORE_CREATE, self,
context=context, port=attrs)
# NOTE(kevinbenton): triggered outside of transaction since it
# emits 'AFTER' events if it creates.
self._ensure_default_security_group(context, attrs['tenant_id'])
此函数就是将port的信息提取出来;
进入第二个函数查看:
def _create_port_db(self, context, port):
attrs = port[port_def.RESOURCE_NAME]
with db_api.context_manager.writer.using(context):
dhcp_opts = attrs.get(edo_ext.EXTRADHCPOPTS, [])
“将port信息写入DB”
port_db = self.create_port_db(context, port)
result = self._make_port_dict(port_db, process_extensions=False)
“通过extension manager调用extension driver的接口”
self.extension_manager.process_create_port(context, attrs, result)
"检查port的sercurity属性;之后的语句都是为port添加不同的字段,至于每个字段的含义
就不一一探究(主要是也还不清楚。。。)"
self._portsec_ext_port_create_processing(context, result, port)
# sgids must be got after portsec checked with security group
sgids = self._get_security_groups_on_port(context, port)
self._process_port_create_security_group(context, result, sgids)
network = self.get_network(context, result['network_id'])
binding = db.add_port_binding(context, result['id'])
mech_context = driver_context.PortContext(self, context, result,
network, binding, None)
self._process_port_binding(mech_context, attrs)
result[addr_apidef.ADDRESS_PAIRS] = (
self._process_create_allowed_address_pairs(
context, result,
attrs.get(addr_apidef.ADDRESS_PAIRS)))
self._process_port_create_extra_dhcp_opts(context, result,
dhcp_opts)
kwargs = {'context': context, 'port': result}
registry.notify(
resources.PORT, events.PRECOMMIT_CREATE, self, **kwargs)
“通过mechanism manager调用merchanism driver的precommit接口
self.mechanism_manager.create_port_precommit(mech_context)
self._setup_dhcp_agent_provisioning_component(context, result)
resource_extend.apply_funcs('ports', result, port_db)
return result, mech_context
再来详细看下create_port_precommit函数:
def create_port_precommit(self, context):
"""Notify all mechanism drivers during port creation.
:raises: DB retriable error if create_network_precommit raises them
See neutron.db.api.is_retriable for what db exception is retriable
or neutron.plugins.ml2.common.MechanismDriverError
if any mechanism driver create_port_precommit call fails.
Called within the database transaction. If a mechanism driver
raises an exception, then a MechanismDriverError is propagated
to the caller, triggering a rollback. There is no guarantee
that all mechanism drivers are called in this case.
"""
self._call_on_drivers("create_port_precommit", context,
raise_db_retriable=True)
通过此方法,依据配置文件mechanism drivers的配置,调用该厂商的内部代码;
接下来看第三个函数:
def _after_create_port(self, context, result, mech_context):
# notify any plugin that is interested in port create events
kwargs = {'context': context, 'port': result}
registry.notify(resources.PORT, events.AFTER_CREATE, self, **kwargs)
try:
“通过mechanism manager调用mechanism driver的postcommit接口,这同之前调用
precommit,通过调用对应厂商的代码完成下一步操作”
self.mechanism_manager.create_port_postcommit(mech_context)
except ml2_exc.MechanismDriverError:
with excutils.save_and_reraise_exception():
LOG.error("mechanism_manager.create_port_postcommit "
"failed, deleting port '%s'", result['id'])
“注意此处的回退操作,若调用失败,则会删除库中已创建的port,以恢复初始状态”
self.delete_port(context, result['id'], l3_port_check=False)
try:
“此步会进入port绑定方法”
bound_context = self._bind_port_if_needed(mech_context)
except ml2_exc.MechanismDriverError:
with excutils.save_and_reraise_exception():
LOG.error("_bind_port_if_needed "
"failed, deleting port '%s'", result['id'])
“回退操作”
self.delete_port(context, result['id'], l3_port_check=False)
return bound_context.current
接下来看port绑定方法,此函数的调用比较多,就不粘贴所有语句了,选取重点说一下:
def _bind_port_if_needed(self, context, allow_notify=False,
need_notify=False, allow_commit=True):
....
“会调用_attempt_binding函数,”
bind_context, need_notify, try_again = self._attempt_binding(
context, need_notify)
....
def _attempt_binding(self, context, need_notify):
....
bind_context = self._bind_port(context)
....
接下来调用_bind_port函数:
def _bind_port(self, orig_context):
# Construct a new PortContext from the one from the previous
# transaction.
port = orig_context.current
orig_binding = orig_context._binding
new_binding = models.PortBinding(
host=orig_binding.host,
vnic_type=orig_binding.vnic_type,
profile=orig_binding.profile,
vif_type=portbindings.VIF_TYPE_UNBOUND,
vif_details=''
)
self._update_port_dict_binding(port, new_binding)
new_context = driver_context.PortContext(
self, orig_context._plugin_context, port,
orig_context.network.current, new_binding, None,
original_port=orig_context.original)
# Attempt to bind the port and return the context with the
# result.
“相信大家看到这个就比较熟悉了,通过mechanism manager调用driver的接口”
self.mechanism_manager.bind_port(new_context)
return new_context
篇幅也很长了,port的create过程就到这里吧