Neutron的整体架构分为三层。
Server —> plugin —>agent
启动server之后neutron会将请求路径和对应的处理函数进行映射。
具体的处理函数由plugin来提供,plugin做的事情有两个:
1)在数据库中创建资源
2)发送rpc请求到具体的agent
所有的plugin提供统一的接口,包括核心资源的增删改查。
neutron原生提供ml2这一plugin,ml2plugin分为类型驱动和机制驱动。
下面从创建network的角度来看一下neutron的整个调用过程。
Ml2 plugin里实现了create_network。
/neutron/neutron/plugins/ml2/plugin.py
@utils.transaction_guard@db_api.retry_if_session_inactive()def create_network(self, context, network): result, mech_context = self._create_network_db(context, network) kwargs = { 'context': context, 'network': result} registry.notify(resources.NETWORK, events.AFTER_CREATE, self, **kwargs) try: self.mechanism_manager.create_network_postcommit(mech_context) except ml2_exc.MechanismDriverError: with excutils.save_and_reraise_exception(): LOG.error(_LE("mechanism_manager.create_network_postcommit " "failed, deleting network '%s'"), result['id']) self.delete_network(context, result['id']) return result
其中比较重要的一个函数是 self._create_network_db,也就是在数据库中创建network。
neutron的核心设计理念就是将资源模型存放在数据库内,然后根据数据库的数据调用agent来做相应的网络配置。
下面看一下_create_network_db的内部实现:
def _create_network_db(self, context, network): net_data = network[attributes.NETWORK] tenant_id = net_data['tenant_id'] session = context.session with session.begin(subtransactions=True): self._ensure_default_security_group(context, tenant_id) net_db = self.create_network_db(context, network) result = self._make_network_dict(net_db, process_extensions=False, context=context) self.extension_manager.process_create_network(context, net_data, result) self._process_l3_create(context, result, net_data) net_data['id'] = result['id'] self.type_manager.create_network_segments(context, net_data, tenant_id) self.type_manager.extend_network_dict_provider(context, result) # Update the transparent vlan if configured if utils.is_extension_supported(self, 'vlan-transparent'): vlt = vlantransparent.get_vlan_transparent(net_data) net_db['vlan_transparent'] = vlt result['vlan_transparent'] = vlt mech_context = driver_context.NetworkContext(self, context, result) self.mechanism_manager.create_network_precommit(mech_context) result[api.MTU] = self._get_network_mtu(result) ... self._apply_dict_extend_functions('networks', result, net_db) return result, mech_context
其中重要的有两步:
1)self._process_l3_create(context, result, net_data)
2)self.type_manager.create_network_segments(context, net_data, tenant_id)
self._process_l3_create
_process_l3_create从字面上来看是用来处理l3的创建,l3指的是三层网络,三层网络是通过
路由器来实现,路由器存在于网络节点。属于不同subnet的虚拟机想要互通必须通过router。
如果一个虚拟机希望联通外网,比如,访问www.google.com,则路由器必须连接了外网网关信息。
在neutron中被称为external_gateway_info。如下图所示,是一个连接了外部网关的路由器。
在服务启动的时候会从配置文件读取出来,并存到数据库中,查看一下ml2_vlan_allocations表,得到如下结果。
MariaDB [neutron]> select * from ml2_vlan_allocations;
+------------------+---------+-----------+
| physical_network | vlan_id | allocated |
+------------------+---------+-----------+
| physnet2 | 1000 | 0 |
| physnet2 | 1001 | 0 |
| physnet2 | 1002 | 0 |
| physnet2 | 1003 | 0 |
| physnet2 | 1004 | 0 |
| physnet2 | 1005 | 0 |
| physnet2 | 1006 | 0 |
| physnet2 | 1007 | 0 |
| physnet2 | 1008 | 0 |
| physnet2 | 1009 | 0 |
| physnet2 | 1010 | 0 |
| physnet2 | 1011 | 0 |
| physnet2 | 1012 | 0 |
| physnet2 | 1013 | 0 |
| physnet2 | 1014 | 0 |
| physnet2 | 1015 | 0 |
| physnet2 | 1016 | 0 |
| physnet2 | 1017 | 0 |
| physnet2 | 1018 | 0 |
| physnet2 | 1019 | 0 |
| physnet2 | 1020 | 0 |
| physnet2 | 1021 | 0 |
| physnet2 | 1022 | 0 |
| physnet2 | 1023 | 0 |
| physnet2 | 1024 | 0 |
| physnet2 | 1025 | 0 |
| physnet2 | 1026 | 0 |
| physnet2 | 1027 | 0 |
| physnet2 | 1028 | 0 |
| physnet2 | 1029 | 0 |
| physnet2 | 1030 | 0 |
+------------------+---------+-----------+
self._add_network_segment(context, network_id, segment)最终会调用ml2/manages.py 里面的函数。
def _allocate_segment(self, session, network_type): driver = self.drivers.get(network_type) return driver.obj.allocate_tenant_segment(session)
而这个函数又会调用driver(VxLAN, Vlan, GRE等)的allocate_tenant_segment函数,来分配对应的segment。
在这里manages.py扮演一个调度者的角色,所有driver的方法调用都使用manages.py进行了一次封装。
plugins想要调用driver里的方法,要通过manages.py里定义的方法,manages.py内部包含了两个重要的manager。
class TypeManager(stevedore.named.NamedExtensionManager)
class MechanismManager(stevedore.named.NamedExtensionManager)
这两个manager把所有的机制驱动和类型驱动都封装了起来。并提供如下函数供plugin调用:
def _call_on_drivers(self, method_name, context, continue_on_failure=False, raise_db_retriable=False): """Helper method for calling a method across all mechanism drivers. """ errors = [] for driver in self.ordered_mech_drivers: try: getattr(driver.obj, method_name)(context) except Exception as e: if raise_db_retriable and db_api.is_retriable(e): with excutils.save_and_reraise_exception(): LOG.debug("DB exception raised by Mechanism driver " "'%(name)s' in %(method)s", { 'name': driver.name, 'method': method_name}, exc_info=e) LOG.exception( _LE("Mechanism driver '%(name)s' failed in %(method)s"), { 'name': driver.name, 'method': method_name} ) errors.append(e) if not continue_on_failure: break if errors: raise ml2_exc.MechanismDriverError( method=method_name, errors=errors )
那么想要调用驱动的方法,只要调用这个函数即可。
类型驱动和机制驱动也定义了抽象api 在neutron/plugins/ml2/driver_api.py内部。
@six.add_metaclass(abc.ABCMeta)
class TypeDriver(object)
@six.add_metaclass(abc.ABCMeta)
class MechanismDriver(object)
以上就是network创建流程的源码解析