【轉載並修改】OpenStack Neutron源碼分析:ovs-neutron-agent啓動源碼解析

轉載自https://blog.csdn.net/canxinghen/article/details/39395957數據庫

 

【小小:原文寫的很好,高屋建瓴的描述了啓動過程的主要步驟。根據原文所在博客的其餘系列文章,多是基於J版進行描述的。我目前讀的代碼是M版。】安全

 

【如下內容提綱挈領的文字摘抄自原文,具體代碼及分析過程是新增長的】網絡

【原文聲明】:app

本博客歡迎轉載,但請保留原做者信息!socket

做者:華爲雲計算工程師 林凱ide

團隊:華爲杭州研發中心OpenStack社區團隊函數

 

引用其中對L2 Agent的組件的介紹:L2Agent一般運行在Hypervisor,與neutron-server經過RPC通訊、監聽並通知設備的變化,建立新的設備來確保網絡segment的正確性,應用security groups規則等。oop

例如,OVS Agent,使用Open vSwitch來實現VLAN, GRE,VxLAN來實現網絡的隔離,還包括了網絡流量的轉發控制。ui

 

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到那個時間,而後繼續循環工做。

相關文章
相關標籤/搜索