neutron ml2 network创建流程源码解析

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创建流程的源码解析

原文地址:https://www.cnblogs.com/zhouqi0505/p/10526340.html

时间: 2024-08-18 19:18:41

neutron ml2 network创建流程源码解析的相关文章

SpringMVC请求流程源码解析

前言 SpringBoot 可以看作是一个配置工具,整合工具,辅助工具,方便了开发工程中的对其他资源的整合,对于许多组件的整合可以达到开箱即用.零配置的效果.SpringBoot 通过引入相应模块对应的 stater 即可整合其他资源,对于web模块的整合亦是如此.下面我们通过源码再次复习一下 springmvc 在处理一个请求的过程中的关键代码,其实要将整个请求的过程说透需要对 web 容器相关的源码足够的熟悉(比如说 Tomcat),本次博文省略这部分的内容,只对 springmvc 的关键

JobTracker启动流程源码级分析

org.apache.hadoop.mapred.JobTracker类是个独立的进程,有自己的main函数.JobTracker是在网络环境中提交及运行MR任务的核心位置. main方法主要代码有两句: 1 //创建jobTracker对象 2 JobTracker tracker = startTracker(new JobConf()); 3 //启动各个服务,包括JT内部一些重要的服务或者线程 4 tracker.offerService(); 一.startTracker(new Jo

Android Activity启动过程源码解析

背景 启动App内部的Activity,Android 6.0 系统概要 系统会为每个App创建一个进程,系统进程和App进程之间通过Binder通信    2个Binder接口 IActivityManager 和 IApplicationThread    几个Binder相关的类    ActivityManagerService extends ActivityManagerNative    ActivityManagerNative extends Binder implements

Activity启动流程源码分析之Launcher启动(二)

1.前述 在前一篇文章中我们简要的介绍Activity的启动流程Activity启动流程源码分析之入门(一),当时只是简单的分析了一下流程,而且在上一篇博客中我们也说了Activity的两种启动方式,现在我们就来分析其中的第一种方式--Launcher启动,这种启动方式的特点是会创建一个新的进程来加载相应的Activity(基于Android5.1源码). 2.Activity启动流程时序图 好啦,接下来我们先看一下Launcher启动Activity的时序图: 好啦,接下来我们将上述时序图用代

Redis的字典(dict)rehash过程源码解析

Redis的内存存储结构是个大的字典存储,也就是我们通常说的哈希表.Redis小到可以存储几万记录的CACHE,大到可以存储几千万甚至上亿的记录(看内存而定),这充分说明Redis作为缓冲的强大.Redis的核心数据结构就是字典(dict),dict在数据量不断增大的过程中,会遇到HASH(key)碰撞的问题,如果DICT不够大,碰撞的概率增大,这样单个hash 桶存储的元素会越来愈多,查询效率就会变慢.如果数据量从几千万变成几万,不断减小的过程,DICT内存却会造成不必要的浪费.Redis的d

多任务编程----Kithara RTS工程源码解析

本文以windows实时拓展Kithara RTS安装目录下的smp文件夹内的TaskSimple项目为例,解读Kithara RTS的实时多任务编程方法. 该项目只有一个工程TaskSimple,工程内的TaskSimple.cpp文件实现了主要功能,使用了Kithara RTS的kernel模块和Task模块 TaskSimple.cpp文件主要由5部分组成,共享内存结构体,三个任务回调函数,一个主函数runSample 共享内存结构体: //------ CallBackData ----

A2dp初始化流程源码分析

蓝牙启动的时候,会涉及到各个profile 的启动.这篇文章分析一下,蓝牙中a2dp profile的初始化流程. 我们从AdapterState.java中对于USER_TURN_ON 消息的处理说起: switch(msg.what) { case USER_TURN_ON: notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON); mPendingCommandState.setTurningOn(true); transit

SpringSecurity 默认表单登录页展示流程源码

SpringSecurity 默认表单登录页展示流程源码 本篇主要讲解 SpringSecurity提供的默认表单登录页 它是如何展示的的流程, 涉及 1.FilterSecurityInterceptor, 2.ExceptionTranslationFilter , 3.DefaultLoginPageGeneratingFilter 过滤器, 并且简单介绍了 AccessDecisionManager 投票机制 ?1.准备工作(体验SpringSecurity默认表单认证) ??1.1 创

Android指令处理流程源码追踪

1.拨号界面输入*#06#,显示IMEI号,这是怎么出来的? 2.如何快速的找出Android平台中的指令? 1. 在DialpadFragment中的EditText注册一个Textchanged的监听器TextWatcher, 当EditText中的内容发生变化时会调用相应的回调函数,TextWatcher是一个接口: public interface TextWatcher extends NoCopySpan { public void beforeTextChanged(CharSeq