转载自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到那个时间,然后继续循环工作。