neutron-l3-agent 初始化流表過程
/usr/bin/neutron-l3-agent --config-file=/etc/neutron/neutron_dvr_compute.conf --config-file=/etc/neutron/dvr_compute_agent.ini
說明:
1 "//" 為 neutron-l3-agent 初始化過程的一個step步驟标記
+------------------------------------------------------------------------------------+
(一) neutron-l3-agent 初始化過程:
+------------------------------------------------------------------------------------+
/usr/bin/neutron-l3-agent 調用neutron.agent.l3_agent.py中的main()方法來啟動neutron-l3-agent服務。main()方法中建立一個加載了neutron.agent.l3.agent.L3NATAgentWithStateReport管理器的server,
然後啟動這個server。launch server時,會調用server的start()方法。
(1) neutron.agent.l3_agent.py 中main()方法啟動過程:
1.1. 初始化 manager: neutron.agent.l3.agent.L3NATAgentWithStateReport:
1.2. 初始化 neutron.service.py 中 class Service(n_rpc.Service)對象,并執行其start()方法。 初始化過程中将 加載 neutron.agent.l3.agent.L3NATAgentWithStateReport 類以及設定一些配置參數。
//step 1.2 中 class Service(n_rpc.Service) start 方法邏輯:
1.2.1 初始化 rpc connection,并建立消費者線程 消費 rpc topic。
1.2.2 建立loop任務周期性調用report_state方法上報 l3-agent 服務的狀态
1.2.3 建立loop周期性的任務調用 neutron.agent.l3.agent.L3NATAgentWithStateReport 中的 periodic_sync_routers_task 方法從北向neutron-server fullsync 目前host上的所有的router_ids。
1.2.4 調用neutron.agent.l3.agent.L3NATAgentWithStateReport 中的after_start 方法處理router loop
//上述步驟 1.2.3 中 fullsync routers處理過程:
初始化 namespace_manager(neutron.agent.l3.namespace_manager.py)執行個體對象。該執行個體對象主要是l3 的router namespace,dvr_snat_ns 以及 dvr_fip_ns 進行管理。如清除ns操作等。
通過plugin_rpc 調用get_router_ids方法從北向擷取目前host上的router_ids。
通過plugin_rpc 調用get_routers方法批量地(一次取sync_routers_chunk_size 個router)從北向擷取目前host上的所有routers。
輪訓 routers,處理router:
将router_id 加入到router namespace中的标記隊列,使其在清除ns時不清楚 router的ns
如果router 為分布式路由:
如果router 存在ext_net_id(即external_gateway_info屬性中的network_id字段存在),将router的fip_ns加入到router namespace中的标記隊列中。
如果router 不存在ext_net_id,且l3 agent配置為dvr_snat 模式,則namespace管理器清除router的 snat namespace。
如果router為HA router:
檢測router的狀态是否與db狀态一緻,如果不一緻,發送router狀态變化通知。
建構RouterUpdate對象,加入到RouterProcessingQueue 的優先級隊列Queue.PriorityQueue中等待處理。RouterUpdate建構參數:
queue.RouterUpdate(
r['id'],
queue.PRIORITY_SYNC_ROUTERS_TASK,
router=r,
timestamp=timestamp) // 不設定action
設定fullsync = False
調整sync_routers_chunk_size 的值
将目前router_info中不在北向擷取routers中的router 建構RouterUpdate對象,加入到RouterProcessingQueue中等待處理。RouterUpdate建構參數:
queue.RouterUpdate(router_id,
queue.PRIORITY_SYNC_ROUTERS_TASK,
timestamp=timestamp,
action=queue.DELETE_ROUTER) // 設定action
// 上述步驟 1.2.4 中 after_start()處理邏輯
(a)啟動一個協程池調用 _process_routers_loop 方法輪詢處理router。處理router的方法為_process_router_update:
按順序從RouterProcessingQueue 的優先級隊列Queue.PriorityQueue中取出RouterUpdate對象。
if update.action == queue.PD_UPDATE:
//Processing IPv6 PD Prefix Update,and continue
if update.action == queue.DELETE_ROUTER 且最後的更新時間小于router的timstamp:
// 将router_id 從記憶體中儲存router更新時間的self.last_update_time字典中删除
if update.action == queue.CREATE_DISTRIBUTED_DHCP:
if update.id in self.router_info:
// continue。此時處理極端情況,當路由更新時,distributed_dhcp_notify 被接受到
如果從記憶體中儲存的_prefetched_routers能夠擷取到router:
将updateRouter中的prefetched_network 儲存到router的prefetched_networks屬性中
if update.action != queue.DELETE_ROUTER and not router:
通過router_id 從北向擷取router,擷取不到,傳回異常。
if update.action == queue.CREATE_DISTRIBUTED_DHCP:
将updateRouter中的prefetched_network 儲存到router的prefetched_networks屬性中,并将router_id儲存到記憶體中的_prefetched_routers字典中
if not router and update.action != queue.DELETE_ROUTER and update.id in self._prefetched_routers
// continue. Avoid removing prefetched router
if not router:
将router_id從記憶體中的_prefetched_routers 字典中删除
安全删除router:
通過router_id從router_info中擷取目前router的router_info
通過namespace_manager 删除router的namespace
發送 router before_delete消息
将router的router_info資訊從router_info中删除
發送 router after_delete消息
l3_agent_extensions_manager 調用配置檔案中的三層agent擴充驅動(driver)調用自身的delete_router方法删除router
更新router的timestamp,使其在processing queue隊列中變為 older events,防止删除的router重新建立。
将router_id從記憶體中的 _fetched_router_ids 字典中删除。
處理相容的路由:(_process_router_if_compatible)
if not self.conf.enable_inat_enat:
建立agent gw port(floating ip gw port)。檢測gw port是否存在,不存在進行建立:
建立fip namespace(fip-${net-id})
通過rpc_plugin從北向neutron-server擷取agent_gateway_port
建立fip namespace:
ip netns add ${fip_namespace}
ip netns exec ${fip_namespace} ip link set lo up
ip netns exec ${fip_namespace} sysctl -w net.ipv4.ip_forward=1
ip netns exec ${fip_namespace} sysctl -w net.ipv4.conf.all.rp_filter=0
ip netns exec ${fip_namespace} sysctl -w net.ipv4.conf.default.rp_filter=0
擷取fg_interface_name(fg-${port_id前11位})
增加fip agent gateway:
如果fip namespace中不存在 fg_interface_name,ovs建立該port。調用 interface_driver(neutron.agent.linux.interface.OVSInterfaceDriver) plug該接口(處理過程在dhcp agent分析過)
fip namespace中初始化路由port. 調用interface_driver(neutron.agent.linux.interface.OVSInterfaceDriver) init_router_port 方法。
在fip namespace中對agent_gateway_port 的每個fixip 執行garp:
python ${python_site_package_dir}/neutron/agent/l3/send_arping.py ${fg_interface_name} ${fixip} ${agent_gateway_port_mac} 1
在fip namespace中的fg_interface_name 接口上增加 agent_gateway_port的gw ip:
ip netns exec ${fip_namespace} ip route replace default via ${gateway_ip}
ip netns exec ${fip_namespace} sysctl -w net.ipv4.conf.${fg_interface_name}.proxy_arp=1
清除fg namespace 無用的port(lo接口除外)
fip ns 初始化完成
if router.get("prefetched_networks"): //router 中包含 prefetched_networks屬性
// 調用_process_prefetched_router 方法在路由中添加 prefetched_networks 路由資訊
如果 router 不在 router_info中:
// 增加router
從router_info中擷取router
調用router_info中的process()方法對router進行處理(router處理的核心邏輯。詳細走讀下期分解)
發送router的 after_create 通知
調用l3_ext_manager 中配置的driver的 add_router方法處理l3 擴充功能
否則:
// 更新router
從router_info中擷取router
發送router的 before_update 通知
調用router_info中的process()方法對router進行處理(router處理的核心邏輯。詳細走讀下期分解)
發送router的 after_update 通知
調用l3_ext_manager 中配置的driver的 add_router方法處理l3 擴充功能
更新routerProcess中RouterUpdate 的timestamp
+------------------end 完成單個RouterUpdate的處理---------------------------------+
(b) 啟動一個協程池調用 _send_router_interface_garp 方法三分鐘一次輪詢處理,向router 發送garp。 對每個router中的每個qr port發送arp。
在router的namespace(qrouter-${router_id})執行指令: python ${python_site_package_dir}/neutron/agent/l3/send_arping.py ${gw_device_name} fa:fa:fa:fa:fa:fa ${qr_fixip} ${count}