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

posted on 2019-05-05 15:23  钱小小  阅读(1037)  评论(0编辑  收藏  举报

导航