首页
登录 | 注册

【openstack】Quantum-LinuxBridge插件-agent

Quantum-LinuxBridge插件-agent

本博客欢迎转发,但请保留原作者(@孔令贤HW)信息!内容系本人学习、研究和总结,如有雷同,实属荣幸!

1      初始化

文件:quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py

1.1    主函数

#============= ============主函数

defmain():

    eventlet.monkey_patch()

    cfg.CONF(args=sys.argv, project='quantum')

 

    # (TODO) gary - swap with common logging

    logging_config.setup_logging(cfg.CONF)

 

    interface_mappings = {}

    # agent使用的配置项

    for mapping in cfg.CONF.LINUX_BRIDGE.physical_interface_mappings:

        try:

            physical_network, physical_interface = mapping.split(':')

            # 更新字典信息,物理网络和物理接口的对应关系

            interface_mappings[physical_network] = physical_interface

            LOG.debug("physical network %s mapped to physical interface %s" %

                      (physical_network, physical_interface))

        except ValueError as ex:

            LOG.error("Invalid physical interface mapping: \'%s\' - %s" %

                      (mapping, ex))

            sys.exit(1)

 

    polling_interval = cfg.CONF.AGENT.polling_interval

    reconnect_interval = cfg.CONF.DATABASE.reconnect_interval

    root_helper = cfg.CONF.AGENT.root_helper

    rpc = cfg.CONF.AGENT.rpc

   

    # 如果在AGENT段配置了rpc

    if rpc:

        plugin = LinuxBridgeQuantumAgentRPC(interface_mappings,

                                            polling_interval,

                                            root_helper)

    # 如果没有配置

    else:

        db_connection_url = cfg.CONF.DATABASE.sql_connection

        plugin = LinuxBridgeQuantumAgentDB(interface_mappings,

                                           polling_interval,

                                           reconnect_interval,

                                           root_helper,

                                           db_connection_url)

    LOG.info("Agent initialized successfully, now running... ")

    # 主函数,内部是个循环

    plugin.daemon_loop()

sys.exit(0)

1.2    使用的RPC类(接收和发送消息)

#============= ============使用RPC的类

classLinuxBridgeQuantumAgentRPC:

 

    def__init__(self, interface_mappings, polling_interval,

                 root_helper):

        self.polling_interval = polling_interval

        self.root_helper = root_helper

        # 创建LinuxBridge对象

        self.setup_linux_bridge(interface_mappings)

        self.setup_rpc(interface_mappings.values())

 

    defsetup_rpc(self, physical_interfaces):

        if physical_interfaces:

            # 获取网络接口的MAC地址

            mac = utils.get_interface_mac(physical_interfaces[0])

        else:

            devices = ip_lib.IPWrapper(self.root_helper).get_devices(True)

            if devices:

                mac = utils.get_interface_mac(devices[0].name)

            else:

                LOG.error("Unable to obtain MAC of any device for agent_id")

                exit(1)

        # agent_id在每一个计算节点上应该是不同的

        self.agent_id = '%s%s' % ('lb', (mac.replace(":", "")))

        LOG.info("RPC agent_id: %s" % self.agent_id)

 

        # topic='q-agent-notifier'

        self.topic = topics.AGENT

        # 创建一个RPC发送端,routing-key='q-plugin'

        self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)

 

        # RPC network init

        self.context = context.RequestContext('quantum', 'quantum',

                                              is_admin=False)

        # Handle updates from service

        self.callbacks = LinuxBridgeRpcCallbacks(self.context,

                                                 self.linux_br)

        self.dispatcher = self.callbacks.create_rpc_dispatcher()

        # Define the listening consumers for the agent

        # 创建两个队列监听者

        # routing-key分别是'q-agent-notifier-network-delete''q-agent-notifier-port-update'

        consumers = [[topics.PORT, topics.UPDATE],

                     [topics.NETWORK, topics.DELETE]]

        self.connection = agent_rpc.create_consumers(self.dispatcher,

                                                     self.topic,

                                                     consumers)

       

        # pyudev库,驱动和硬件设备管理

        self.udev = pyudev.Context()

        # pyudev.Monitor是一个同步的设备事件监听器, connecting to the kernel daemon through netlink

        monitor = pyudev.Monitor.from_netlink(self.udev)

        # 过滤事件

        monitor.filter_by('net')

1.3    循环处理

#============= ============agent的循环处理方法

    defdaemon_loop(self):

        sync = True

        devices = set()

 

        LOG.info("LinuxBridge Agent RPC Daemon Started!")

 

        whileTrue:

            start = time.time()

            if sync:

                LOG.info("Agent out of sync with plugin!")

                devices.clear()

                sync = False

 

            # 使用pyudev库获取本机网络设备实时信息,如果与上次保存信息相同直接返回进行下一次循环

            device_info = self.update_devices(devices)

 

            # notify plugin about device deltas

            if device_info:

                LOG.debug("Agent loop has new devices!")

                # If treat devices fails - indicates must resync with plugin

                # 处理增加或删除设备信息的主函数<=== 重要!

                sync = self.process_network_devices(device_info)

                devices = device_info['current']

 

            # sleep till end of polling interval

            elapsed = (time.time() - start)

            if (elapsed < self.polling_interval):

                time.sleep(self.polling_interval - elapsed)

            else:

                LOG.debug("Loop iteration exceeded interval (%s vs. %s)!",

                          self.polling_interval, elapsed)

 

以新增设备为例:

1. 首先向上层查询新增设备信息

2. 根据设备的admin_state_up状态调用LinuxBridge对象方法

            physical_interface = self.interface_mappings.get(physical_network)

            ifnot physical_interface:

                LOG.error("No mapping for physical network %s" %

                          physical_network)

                returnFalse

 

            # flat模式

            if int(vlan_id) == lconst.FLAT_VLAN_ID:

                self.ensure_flat_bridge(network_id, physical_interface)

            # vlan模式

            else:

                # 为接口添加vlan并创建网桥(如果没有的话)

                self.ensure_vlan_bridge(network_id, physical_interface,

                                        vlan_id)

        if utils.execute(['brctl', 'addif', bridge_name, tap_device_name],

                         root_helper=self.root_helper):

            returnFalse

 

        LOG.debug("Done adding device %s to bridge %s" % (tap_device_name,

                                                          bridge_name))

        returnTrue

3. 如果是vlan类型网络

    defensure_vlan_bridge(self, network_id, physical_interface, vlan_id):

        """Create a vlan and bridge unless they already exist."""

        interface = self.ensure_vlan(physical_interface, vlan_id)

        bridge_name = self.get_bridge_name(network_id)

        self.ensure_bridge(bridge_name, interface)

        return interface

2      消息处理

如下图,在LinuxBridge插件的agent中只接收两种消息的处理。


【openstack】Quantum-LinuxBridge插件-agent

 

一个是删除network,另一个是更新port

2.1    network_delete

    defnetwork_delete(self, context, **kwargs):

        LOG.debug("network_delete received")

        network_id = kwargs.get('network_id')

        # 获取逻辑网络对应的网桥名称,前缀"brq"

        bridge_name = self.linux_br.get_bridge_name(network_id)

        LOG.debug("Delete %s", bridge_name)

        self.linux_br.delete_vlan_bridge(bridge_name)

    defdelete_vlan_bridge(self, bridge_name):

        # 调用命令查询网桥是否存在

        if self.device_exists(bridge_name):

            # 获取网桥上的所有接口(列举目录/sys/devices/virtual/net/${bridge_name}/brif/

            interfaces_on_bridge = self.get_interfaces_on_bridge(bridge_name)

            for interface in interfaces_on_bridge:

                # 通过命令删除接口

                self.remove_interface(bridge_name, interface)

                for physical_interface in self.interface_mappings.itervalues():

                    # 若是flat类型的网络

                    if physical_interface == interface:

                        # This is a flat network => return IP's from bridge to

                        # interface

                        ips, gateway = self.get_interface_details(bridge_name)

                        self.update_interface_ip_details(interface,

                                                         bridge_name,

                                                         ips, gateway)

                    else:

                        if interface.startswith(physical_interface):

                            # 调用命令删除接口上创建的vlan

                            self.delete_vlan(interface)

 

            LOG.debug("Deleting bridge %s" % bridge_name)

            if utils.execute(['ip', 'link', 'set', bridge_name, 'down'],

                             root_helper=self.root_helper):

                return

            # 删除网桥

            if utils.execute(['brctl', 'delbr', bridge_name],

                             root_helper=self.root_helper):

                return

            LOG.debug("Done deleting bridge %s" % bridge_name)

 

        else:

            LOG.error("Cannot delete bridge %s, does not exist" % bridge_name)

2.2    port_update

    defport_update(self, context, **kwargs):

        LOG.debug("port_update received")

        port = kwargs.get('port')

        # 若操作状态为True,增加设备

        if port['admin_state_up']:

            vlan_id = kwargs.get('vlan_id')

            # create the networking for the port

            self.linux_br.add_interface(port['network_id'],

                                        vlan_id,

                                        port['id'])

        # 删除设备

        else:

            bridge_name = self.linux_br.get_bridge_name(port['network_id'])

            tap_device_name = self.linux_br.get_tap_device_name(port['id'])

            self.linux_br.remove_interface(bridge_name, tap_device_name)

本博客欢迎转发,但请保留原作者(@孔令贤HW)信息!内容系本人学习、研究和总结,如有雷同,实属荣幸!



2020 jeepxie.net webmaster#jeepxie.net
10 q. 0.009 s.
京ICP备10005923号