openstack之neutron代码分析---(1)neutron初始化流程

Neutron是openstack中用于管理网络的项目。neutron代码的入口配置文件neutron/setup.cfg,我们可以通过这个文件了解整个项目的代码结构。文章中代码为neutron kilo版本。部分setup.cfg内容如下:

…
[entry_points]
console_scripts = 
	…
	neutron-l3-agent = neutron.agent.l3.agent:main
	neutron-lbaas-agent = neutron.services.loadbalancer.agent.agent:main
	neutron-linuxbridge-agent = neutron.plugins.linuxbridge.agent.linuxbridge_neutron_agent:main
	neutron-metadata-agent = neutron.agent.metadata.agent:main
…
	neutron-nvsd-agent = neutron.plugins.oneconvergence.agent.nvsd_neutron_agent:main
	neutron-openvswitch-agent = neutron.plugins.openvswitch.agent.ovs_neutron_agent:main
…
	neutron-server = neutron.server:main
…
neutron.core_plugins = 
	…
	hyperv = neutron.plugins.hyperv.hyperv_neutron_plugin:HyperVNeutronPlugin
	ibm = neutron.plugins.ibm.sdnve_neutron_plugin:SdnvePluginV2
	midonet = neutron.plugins.midonet.plugin:MidonetPluginV2
	ml2 = neutron.plugins.ml2.plugin:Ml2Plugin
…

neutron-l3-agent:l3 agent部署在计算节点或者网络节点上,负责3层虚拟网络的管理。根据setup.cfg文件可以看出neutron-l3-agent的代码路径是neutron\agent\l3\agent

neutron-openvswitch-agent:Open vSwitch Agent部署在计算节点或者网络节点上,进行管理OVS虚拟交换机。根据setup.cfg文件可以看出neutron-openvswitch-agent的代码路径是neutron\plugins\openvswitch\agent.ovs_neutron_agent

neutron-server:是Neutron中唯一的一个服务进程,负责接收用户的RESTful API请求并分发处理给各种agen来完成这些的任务。根据setup.cfg文件可以看出neutron代码路径是neutron\server

ML2Plugin:用于提供二层虚拟网络,实现了network/subnet/port资源的操作,这些操作最终由Plugin通过RPC调用OpenvSwitch Agent来完成。根据setup.cfg文件可以看出代码路径是 neutron\plugins\ml2\plugin\Ml2Plugin

neutron初始化流程:

1.server初始化

server初始化文件:neutron\neutron\server\__init__.py

def main():
    # the configuration will be read into the cfg.CONF global data structure
    config.init(sys.argv[1:])
    ....
    try:
        pool = eventlet.GreenPool()
        neutron_api = service.serve_wsgi(service.NeutronApiService)
        api_thread = pool.spawn(neutron_api.wait)
        try:
            neutron_rpc = service.serve_rpc()
            ....
        else:
            rpc_thread = pool.spawn(neutron_rpc.wait)
            # api and rpc should die together.  When one dies, kill the other.
            rpc_thread.link(lambda gt: api_thread.kill())
            api_thread.link(lambda gt: rpc_thread.kill())
        pool.waitall()
    ....

main方法的核心就是serve_wsgi、serve_rpc两个方法调用,分别创建api服务和rpc服务。

1.1api服务初始化

api服务的实现是service.NeutronApiService,这是一个符合WSGI规范的app,通过paste进行配置,paste文件位置可以在配置文件中指定,默认是/etc/neutron/api-paste.ini,在代码中是etc/api-paste.ini。查看api-paste.ini可以确定v2版api的实现是在neutron.api.v2.router:APIRouter

 [app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory

APIRouter在构造时,会根据配置文件core_plugin的配置加载plugin、extension管理器。所在文件:

neutron\neutron\api\v2\router.py

class APIRouter(wsgi.Router):
    @classmethod
    def factory(cls, global_config, **local_config):
        return cls(**local_config)
 
    def __init__(self, **local_config):
        mapper = routes_mapper.Mapper()
        plugin = manager.NeutronManager.get_plugin()
        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
        ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)

1.2.rpc服务初始化

serve_rpc函数定义文件:neutron\neutron\service.py

def serve_rpc():
    plugin = manager.NeutronManager.get_plugin()
    ....
    try:
        rpc = RpcWorker(plugin)
        if cfg.CONF.rpc_workers < 1:
            rpc.start()
            return rpc
        ....


首先会根据配置文件core_plugin的配置加载plugin,然后创建RpcWorker,开始监听rpc;通过调用_plugin.start_rpc_listeners进行监听。

 

以ml2 plugin为例,在它的start_rpc_listener方法中,创建neutron.plugin.ml2.rpc.RpcCallbacks类的实例,并创建了dispatcher处理'q-plugin' topic

ml2 plugin所在文件:neutron/plugins/ml2/plugin.py

    def start_rpc_listeners(self):
        self.endpoints = [rpc.RpcCallbacks(self.notifier, self.type_manager),
                          securitygroups_rpc.SecurityGroupServerRpcCallback(),
                          dvr_rpc.DVRServerRpcCallback(),
                          dhcp_rpc.DhcpRpcCallback(),
                          agents_db.AgentExtRpcCallback(),
                          metadata_rpc.MetadataRpcCallback()]
        self.topic = topics.PLUGIN
        self.conn = n_rpc.create_connection(new=True)
        self.conn.create_consumer(self.topic, self.endpoints,
                                  fanout=False)
        return self.conn.consume_in_threads()
 

 ML2Plugin初始化时,针对agent创建自己的消息队列(notify,生产者)(topics.AGENT)以便向agent发送rpc请求,同时订阅ml2 Agent消息队列的消息(consumer,消费者)(topics.PLUGIN)以便接收来自agent的rpc请求。

同样,ml2 Agent初始化时,也会创建自己的消息队列(notify,生产者)(topics.PLUGIN)来向plugin发送rpc请求,同时订阅ML2Plugin消息队列的消息(consumer,消费者)(topics.AGENT)来接收来自plugin的rpc请求。

消息队列的生成者类(xxxxNotifyAPI)和对应的消费者类(xxxxRpcCallback)定义有相同的接口函数,生产者类中的函数主要作用是rpc调用消费者类中的同名函数,消费者类中的函数执行实际的动作。

如:xxxNotifyAPI类中定义有network_delete()函数,则xxxRpcCallback类中也会定义有network_delete()函数。xxxNotifyAPI::network_delete()通过rpc调用xxxRpcCallback::network_delete()函数,xxxRpcCallback::network_delete()执行实际的network  delete删除动作。

RpcCallbacks类中的方法与neutron.agent.rpc.PluginApi的方法是对应的

2.agent初始化

以常用的openvswitch agent为例,可以执行以下命令启动agent服务

$service neutron-openvswitch-agent start

setup.cfg配置文件的以下内容可以知道,实际执行的方法是neutron.plugins.openvswitch.agent.ovs_neutron_agent:main

[entry_points]
console-scripts = 
    ...
    neutron-openvswitch-agent = neutron.plugins.openvswitch.agent.ovs_neutron_agent:main
    ...

2.1.neutron/plugins/openvswitch/agent/ovs_neutron_agent.py:main

def main():
    ...
    try:
        # 从配置文件中读取agent的配置,主要是network_mappings,各个bridges名称
        agent_config = create_agent_config_map(cfg.CONF)
    except ValueError as e:
        LOG.error(_('%s Agent terminated!'), e)
        sys.exit(1)
    ...
    # 创建agent实例
    agent = OVSNeutronAgent(**agent_config)
    signal.signal(signal.SIGTERM, handle_sigterm)
    # Start everything.
    LOG.info(_("Agent initialized successfully, now running... "))
    agent.daemon_loop()
    sys.exit(0)

2.2.neutron/plugins/openvswitch/agent/ovs_neutron_agent.py:__init__

OVSNeutronAgentdocstring中,概要说明了agent实现虚拟的方式,有以下几点:

· 创建br-int, br-tun以及每个物理网络接口一个bridge

· 虚拟机的虚拟网卡都会接入到br-int。使用同一个虚拟网络的虚拟网卡共享一个localVLAN(与外部网络的VLAN无关,vlan id可以重叠)。这个localVLAN id会映射到外部网络的某个VLAN id

· 对于network_typeVLAN或者FLAT的网络,在br-int和各个物理网络bridge之间创建一个虚拟网卡,用于限定流规则、映射或者删除VLAN id等处理。

· 对于network_typeGRE的,每个租户在不同hypervisor之间的网络通信通过一个逻辑交换机标识符(Logical Switch identifier)进行区分,并创建一个连通各个hypervisorbr-tun的通道(tunnel)网络。Port patching用于连通br-int和各个hypervisorbr-tun上的VLAN

class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin,
                      l2population_rpc.L2populationRpcCallBackMixin):
 
    def __init__(self, integ_br, tun_br, local_ip,
                 bridge_mappings, root_helper,
                 polling_interval, tunnel_types=None,
                 veth_mtu=None, l2_population=False,
                 minimize_polling=False,
                 ovsdb_monitor_respawn_interval=(
                     constants.DEFAULT_OVSDBMON_RESPAWN)):
        ...
        # local VLAN id范围是[1, 2094]
        self.available_local_vlans = set(xrange(q_const.MIN_VLAN_TAG,
                                                q_const.MAX_VLAN_TAG))
        ...
        # 创建br-int,重置流表规则等,通过调用brctl, ovs-vsctl, ip等命令实现
        self.int_br = ovs_lib.OVSBridge(integ_br, self.root_helper)
        self.setup_integration_br()
        self.int_br.set_secure_mode()
        # Stores port update notifications for processing in main rpc loop
        self.updated_ports = set()
        # 配置plugin的rpcapi连接(topic='q-plugin',接口neutron.agent.rpc.py:PluginApi)并监听其它服务对agent的rpc的调用(topic='q-agent-notifier')
        self.setup_rpc()
        # 配置文件中传入的参数
        self.bridge_mappings = bridge_mappings
        # 给每个mapping创建一个bridge,并连接到br-int
        self.setup_physical_bridges(self.bridge_mappings)
        self.local_vlan_map = {}
        # 创建tunnel的代码省略
        # Security group agent supprot
        self.sg_agent = OVSSecurityGroupAgent(self.context,
                                              self.plugin_rpc,                    
                                              root_helper)                        
 

2.3.neutron/plugins/openvswitch/agent/ovs_neutron_agent.py:daemon_loop

该方法是服务的消息循环方法,主要逻辑在它调用的rpc_loop方法中。

def rpc_loop(self, polling_manager=None):
    while True:
        ...
        # 从br-int确定配置更新或者删除的端口信息
        port_info = self.scan_ports(reg_ports, updated_ports_copy)
        ports = port_info['current']
        ...
        # Secure and wire/unwire VIFs and update their status
        # on Neutron server
        if (self._port_info_has_changes(port_info) or
            self.sg_agent.firewall_refresh_needed() or
            ovs_restarted):
            # If treat devices fails - must resync with plugin
            # 这个方法会从plugin查询port的详情,根据port的admin_state_up状态,分别执行self.port_bound()或者self.port_dead()
            # 并调用plugin rpc的update_device_up或update_device_down方法更新端口状态
            sync = self.process_network_ports(port_info,
                                              ovs_restarted)
 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
neutron 的源码流程可以分为以下几个步骤: 1. 启动服务:neutron 服务的启动是通过 `neutron-server` 命令来完成的。在启动时,neutron 会读取配置文件,并进行初始化操作。 2. API 接口:当用户发送网络请求时,neutron 的 API 接口会接收请求,并根据请求的 URL 来确定请求的类型和目标对象。API 接口会将请求转发给相应的插件处理。 3. 插件处理:插件会根据请求的类型和目标对象来处理请求。插件可能需要调用 neutron 的 API 接口、代理接口等来完成网络功能。 4. 代理处理:当插件需要在计算节点上实现网络功能时,代理会接收插件的请求,并根据请求的类型和目标对象来处理请求。代理会调用相应的驱动程序来实现网络功能。 5. 数据库操作:neutron 的插件和代理需要对数据库进行操作,以存储和管理网络相关的数据。数据库的操作是通过 SQLAlchemy 来实现的。 6. 异常处理:当出现异常时,neutron 会根据异常的类型和来源来进行相应的处理,如记录日志、发送邮件等。异常处理是通过 Python 的异常机制来实现的。 7. 响应处理:当插件和代理完成请求处理后,会将处理结果返回给 API 接口。API 接口会根据结果的类型和状态来生成响应,并将响应发送给用户。 总之,neutron 的源码流程涉及多个模块和组件的协同工作,需要深入了解网络技术和 OpenStack 的架构设计,同时需要具备良好的编程能力和调试能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值