zoukankan      html  css  js  c++  java
  • 【转载并修改】OpenStack Neutron源码分析:ovs-neutron-agent启动源码解析

    转载自https://blog.csdn.net/canxinghen/article/details/39395957

    【小小:原文写的很好,高屋建瓴的描述了启动过程的主要步骤。根据原文所在博客的其他系列文章,可能是基于J版进行描述的。我目前读的代码是M版。】

    【以下内容提纲挈领的文字摘抄自原文,具体代码及分析过程是新增加的】

    【原文声明】:

    本博客欢迎转载,但请保留原作者信息!

    作者:华为云计算工程师 林凯

    团队:华为杭州研发中心OpenStack社区团队

    引用其中对L2 Agent的组件的介绍:L2Agent通常运行在Hypervisor,与neutron-server通过RPC通信、监听并通知设备的变化,创建新的设备来确保网络segment的正确性,应用security groups规则等。

    例如,OVS Agent,使用Open vSwitch来实现VLAN, GRE,VxLAN来实现网络的隔离,还包括了网络流量的转发控制。

    OVS Agent组件启动大致流程如下图所示:

     1 # 小小:这里引用的是M版代码
     2 def main(bridge_classes):
     3     prepare_xen_compute()
     4     validate_tunnel_config(cfg.CONF.AGENT.tunnel_types, cfg.CONF.OVS.local_ip)
     5 
     6     try:
     7         agent = OVSNeutronAgent(bridge_classes, cfg.CONF)
     8     except (RuntimeError, ValueError) as e:
     9         LOG.error(_LE("%s Agent terminated!"), e)
    10         sys.exit(1)
    11     agent.daemon_loop()

    上述代码中,最重要的是:

    (第7行)实例化一个OVSNeutronAgent,在实例初始化过程中,完成OVS Agent的一系列初始化工作。

    (第11行)函数一直在循环检查一些状态,发现状态发生变化,执行相应的操作。

    接下来,首先仔细分析OVSNeutronAgent实例化,看它做了哪些初始化工作:

      1 def __init__(self, bridge_classes, conf=None):
      2         '''Constructor.
      3 
      4         :param bridge_classes: a dict for bridge classes.
      5         :param conf: an instance of ConfigOpts
      6         '''
      7         super(OVSNeutronAgent, self).__init__()
      8         self.conf = conf or cfg.CONF
      9         # 【!!!】BaseOVS类中利用OVSDbVsctl类执行ovs的各种操作命令
     10         self.ovs = ovs_lib.BaseOVS()
     11         agent_conf = self.conf.AGENT
     12         ovs_conf = self.conf.OVS
     13 
     14         self.fullsync = False
     15         # init bridge classes with configured datapath type.
     16         # 【?】datapath_type在配置文件中为system
     17         self.br_int_cls, self.br_phys_cls, self.br_tun_cls = (
     18             functools.partial(bridge_classes[b],
     19                               datapath_type=ovs_conf.datapath_type)
     20             for b in ('br_int', 'br_phys', 'br_tun'))
     21 
     22         self.use_veth_interconnection = ovs_conf.use_veth_interconnection
     23         self.veth_mtu = agent_conf.veth_mtu
     24         # 保存尚未被使用的local vlan
     25         self.available_local_vlans = set(moves.range(p_const.MIN_VLAN_TAG,
     26                                                      p_const.MAX_VLAN_TAG))
     27         # 配置文件中tunnel_types = vxlan
     28         self.tunnel_types = agent_conf.tunnel_types or []
     29         self.l2_pop = agent_conf.l2_population
     30         # TODO(ethuleau): Change ARP responder so it's not dependent on the
     31         #                 ML2 l2 population mechanism driver.
     32         # 是否启用了DVR模式 配置中为True
     33         self.enable_distributed_routing = agent_conf.enable_distributed_routing
     34         self.arp_responder_enabled = agent_conf.arp_responder and self.l2_pop
     35 
     36         host = self.conf.host
     37         self.agent_id = 'ovs-agent-%s' % host
     38 
     39         if self.tunnel_types:
     40             self.enable_tunneling = True
     41         else:
     42             self.enable_tunneling = False
     43 
     44         # Validate agent configurations
     45         self._check_agent_configurations()
     46 
     47         # Keep track of int_br's device count for use by _report_state()
     48         self.int_br_device_count = 0
     49 
     50         # 【!!!】创建br-int网桥
     51         self.int_br = self.br_int_cls(ovs_conf.integration_bridge)
     52         self.setup_integration_br()
     53         # Stores port update notifications for processing in main rpc loop
     54         self.updated_ports = set()
     55         # Stores port delete notifications
     56         self.deleted_ports = set()
     57 
     58         self.network_ports = collections.defaultdict(set)
     59         # keeps association between ports and ofports to detect ofport change
     60         self.vifname_to_ofport_map = {}
     61         # 【!!!】创建RPC相关客户端(请求plugin提供服务)、服务端(响应plugin的资源变化通知)
     62         self.setup_rpc()
     63         # 示例配置bridge_mappings = test_vlan_net:brqd8d5c382-f7
     64         self.bridge_mappings = self._parse_bridge_mappings(
     65             ovs_conf.bridge_mappings)
     66         # 【!!!】创建物理网的网桥
     67         self.setup_physical_bridges(self.bridge_mappings)
     68         # 【?】
     69         self.local_vlan_map = {}
     70 
     71         self._reset_tunnel_ofports()
     72 
     73         self.polling_interval = agent_conf.polling_interval
     74         self.minimize_polling = agent_conf.minimize_polling
     75         self.ovsdb_monitor_respawn_interval = (
     76             agent_conf.ovsdb_monitor_respawn_interval or
     77             constants.DEFAULT_OVSDBMON_RESPAWN)
     78         self.local_ip = ovs_conf.local_ip
     79         self.tunnel_count = 0
     80         self.vxlan_udp_port = agent_conf.vxlan_udp_port
     81         self.dont_fragment = agent_conf.dont_fragment
     82         self.tunnel_csum = agent_conf.tunnel_csum
     83         self.tun_br = None
     84         self.patch_int_ofport = constants.OFPORT_INVALID
     85         self.patch_tun_ofport = constants.OFPORT_INVALID
     86         if self.enable_tunneling:
     87             # The patch_int_ofport and patch_tun_ofport are updated
     88             # here inside the call to setup_tunnel_br()
     89             # 【!!!】创建br-tun
     90             self.setup_tunnel_br(ovs_conf.tunnel_bridge)
     91 
     92         # 【?】当前没有配置extension(entry文件中仅有一个qos)
     93         self.init_extension_manager(self.connection)
     94 
     95         # 【!!!】DVR相关的主机mac、端口流表的处理类
     96         self.dvr_agent = ovs_dvr_neutron_agent.OVSDVRNeutronAgent(
     97             self.context,
     98             self.dvr_plugin_rpc,
     99             self.int_br,
    100             self.tun_br,
    101             self.bridge_mappings,
    102             self.phys_brs,
    103             self.int_ofports,
    104             self.phys_ofports,
    105             self.patch_int_ofport,
    106             self.patch_tun_ofport,
    107             host,
    108             self.enable_tunneling,
    109             self.enable_distributed_routing)
    110 
    111         if self.enable_tunneling:
    112             # 【!!!】下发br-tun的初始化流表
    113             self.setup_tunnel_br_flows()
    114 
    115         # 【!!!】下发DVR的初始化流表
    116         self.dvr_agent.setup_dvr_flows()
    117 
    118         # 【?】创建辅助桥,现在看来为空
    119         # Collect additional bridges to monitor
    120         self.ancillary_brs = self.setup_ancillary_bridges(
    121             ovs_conf.integration_bridge, ovs_conf.tunnel_bridge)
    122 
    123         # In order to keep existed device's local vlan unchanged,
    124         # restore local vlan mapping at start
    125         # 【!!!】扫描br-int的ports,找已被使用的vlan号和network的对应关系
    126         self._restore_local_vlan_map()
    127 
    128         # Security group agent support
    129         # 【!!!】调用xxxFirewallDriver利用iptables实现安全组规则
    130         # 使用到的driver=iptables_hybrid(不用ovs实现,在qbr上实现)
    131         self.sg_agent = sg_rpc.SecurityGroupAgentRpc(self.context,
    132                 self.sg_plugin_rpc, self.local_vlan_map,
    133                 defer_refresh_firewall=True, integration_bridge=self.int_br)
    134 
    135         # we default to False to provide backward compat with out of tree
    136         # firewall drivers that expect the logic that existed on the Neutron
    137         # server which only enabled hybrid plugging based on the use of the
    138         # hybrid driver.
    139         hybrid_plug = getattr(self.sg_agent.firewall,
    140                               'OVS_HYBRID_PLUG_REQUIRED', False)
    141         # 当前场景配置为True
    142         self.prevent_arp_spoofing = (
    143             agent_conf.prevent_arp_spoofing and
    144             not self.sg_agent.firewall.provides_arp_spoofing_protection)
    145 
    146         #TODO(mangelajo): optimize resource_versions to only report
    147         #                 versions about resources which are common,
    148         #                 or which are used by specific extensions.
    149         # 状态报告的内容,由_report_state()函数上报给plugin
    150         self.agent_state = {
    151             'binary': 'neutron-openvswitch-agent',
    152             'host': host,
    153             'topic': n_const.L2_AGENT_TOPIC,
    154             'configurations': {'bridge_mappings': self.bridge_mappings,
    155                                'tunnel_types': self.tunnel_types,
    156                                'tunneling_ip': self.local_ip,
    157                                'l2_population': self.l2_pop,
    158                                'arp_responder_enabled':
    159                                self.arp_responder_enabled,
    160                                'enable_distributed_routing':
    161                                self.enable_distributed_routing,
    162                                'log_agent_heartbeats':
    163                                agent_conf.log_agent_heartbeats,
    164                                'extensions': self.ext_manager.names(),
    165                                'datapath_type': ovs_conf.datapath_type,
    166                                'ovs_capabilities': self.ovs.capabilities,
    167                                'vhostuser_socket_dir':
    168                                ovs_conf.vhostuser_socket_dir,
    169                                portbindings.OVS_HYBRID_PLUG: hybrid_plug},
    170             'resource_versions': resources.LOCAL_RESOURCE_VERSIONS,
    171             'agent_type': agent_conf.agent_type,
    172             'start_flag': True}
    173 
    174         report_interval = agent_conf.report_interval
    175         if report_interval:
    176             heartbeat = loopingcall.FixedIntervalLoopingCall(
    177                 self._report_state)
    178             heartbeat.start(interval=report_interval)
    179         # 【!!!】这里初始化的变量均会用在rpc_loop()中
    180         # Initialize iteration counter
    181         self.iter_num = 0
    182         self.run_daemon_loop = True
    183 
    184         self.catch_sigterm = False
    185         self.catch_sighup = False
    186 
    187         # 【!!!】开始接收消息,处理RPC请求
    188         # The initialization is complete; we can start receiving messages
    189         self.connection.consume_in_threads()
    190 
    191         self.quitting_rpc_timeout = agent_conf.quitting_rpc_timeout

    注意代码中的【!!!】和【?】注释,叹号表示主要过程和函数,问号表示没看懂。

     

     

    最后把run_daemon_loop变量置为True,开始循环查询的工作。当run_daemon_loop变量置为True,main函数调用daemon_loop函数,之后调用rpc_loop函数,我们来看下rpc_loop函数都完成了哪些工作。

    rpc_loop做的工作很明显就是进行循环地查询一些状态,根据这些状态,进行相应的操作,其中最重要的工作就是扫描数据库中的ports信息,然后对这些信息进行处理。

    获取到port_info之后就要根据这些信息,对port进行真正的操作,真正的操作就在函数process_network_ports中进行。

    从代码的解释可以看到,process_network_ports完成了port的添加,删除和更新的操作。之后循环检测是否已经到了循环间隔,如果还没有到间隔时间就sleep到那个时间,然后继续循环工作。

  • 相关阅读:
    kmp模板
    2017 ACM/ICPC Asia Regional Shenyang Online transaction transaction transaction
    2017 ACM/ICPC Asia Regional Shenyang Online 12 card card card
    KMP
    最长不下降子序列
    codeforces round 433 D. Jury Meeting
    codeforces round 433 C. Planning 贪心
    hdu 5792 线段树+离散化+思维
    hdu 5792 树状数组+离散化+思维
    hdu 5791 思维dp
  • 原文地址:https://www.cnblogs.com/qxxnxxFight/p/10791714.html
Copyright © 2011-2022 走看看