1 初始化

 

檔:quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py

 

1.1 主函數

 

#============= ============主函數

 

def main():

 

eventlet.monkey_patch()

 

cfg.CONF(args=sys.argv, project='quantum')




# (TODO) gary - swap with common logging

 

logging_config.setup_logging(cfg.CONF)




interface_mappings = {}

 

# agent使用的配置項

 

for mapping in cfg.CONF.LINUX_BRIDGE.physical_interface_mappings:

 

try:

 

physical_network, physical_interface = mapping.split(':')

 

# 更新字典資訊,物理網絡和物理介面的對應關系

 

interface_mappings[physical_network] = physical_interface

 

LOG.debug("physical network %s mapped to physical interface %s" %

 

(physical_network, physical_interface))

 

except ValueError as ex:

 

LOG.error("Invalid physical interface mapping: \'%s\' - %s" %

 

(mapping, ex))

 

sys.exit(1)




polling_interval = cfg.CONF.AGENT.polling_interval

 

reconnect_interval = cfg.CONF.DATABASE.reconnect_interval

 

root_helper = cfg.CONF.AGENT.root_helper

 

rpc = cfg.CONF.AGENT.rpc




# 如果在AGENT段配置了rpc

 

if rpc:

 

plugin = LinuxBridgeQuantumAgentRPC(interface_mappings,

 

polling_interval,

 

root_helper)

 

# 如果沒有配置

 

else:

 

db_connection_url = cfg.CONF.DATABASE.sql_connection

 

plugin = LinuxBridgeQuantumAgentDB(interface_mappings,

 

polling_interval,

 

reconnect_interval,

 

root_helper,

 

db_connection_url)

 

LOG.info("Agent initialized successfully, now running... ")

 

# 主函數,內部是個循環

 

plugin.daemon_loop()

 

sys.exit(0)

 

1.2 使用的RPC類(接收和發送消息)

 

#============= ============使用RPC的類

 

class LinuxBridgeQuantumAgentRPC:




def __init__(self, interface_mappings, polling_interval,

 

root_helper):

 

self.polling_interval = polling_interval

 

self.root_helper = root_helper

 

# 創建LinuxBridge對象

 

self.setup_linux_bridge(interface_mappings)

 

self.setup_rpc(interface_mappings.values())




def setup_rpc(self, physical_interfaces):

 

if physical_interfaces:

 

# 獲取網絡介面的MAC位址

 

mac = utils.get_interface_mac(physical_interfaces[0])

 

else:

 

devices = ip_lib.IPWrapper(self.root_helper).get_devices(True)

 

if devices:

 

mac = utils.get_interface_mac(devices[0].name)

 

else:

 

LOG.error("Unable to obtain MAC of any device for agent_id")

 

exit(1)

 

# agent_id在每一個計算節點上應該是不同的

 

self.agent_id = '%s%s' % ('lb', (mac.replace(":", "")))

 

LOG.info("RPC agent_id: %s" % self.agent_id)




# topic='q-agent-notifier'

 

self.topic = topics.AGENT

 

# 創建一個RPC發送端,routing-key='q-plugin'

 

self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)




# RPC network init

 

self.coNtext = coNtext.RequestCoNtext('quantum', 'quantum',

 

is_admin=False)

 

# Handle updates from service

 

self.callbacks = LinuxBridgeRpcCallbacks(self.coNtext,

 

self.linux_br)

 

self.dispatcher = self.callbacks.create_rpc_dispatcher()

 

# Define the listening consumers for the agent

 

# 創建兩個隊列監聽者

 

# routing-key分別是'q-agent-notifier-network-delete'和'q-agent-notifier-port-update'

 

consumers = [[topics.PORT, topics.UPDATE],

 

[topics.NETWORK, topics.DELETE]]

 

self.connection = agent_rpc.create_consumers(self.dispatcher,

 

self.topic,

 

consumers)




# pyudev庫,驅動和硬體設備管理

 

self.udev = pyudev.CoNtext()

 

# pyudev.Monitor是一個同步的設備事件監聽器, connecting to the kernel daemon through netlink

 

monitor = pyudev.Monitor.from_netlink(self.udev)

 

# 過濾事件

 

monitor.filter_by('net')

 

1.3 循環處理

 

#============= ============agent的循環處理方法

 

def daemon_loop(self):

 

sync = True

 

devices = set()




LOG.info("LinuxBridge Agent RPC Daemon Started!")




while True:

 

start = time.time()

 

if sync:

 

LOG.info("Agent out of sync with plugin!")

 

devices.clear()

 

sync = False




# 使用pyudev庫獲取本機網絡設備實時資訊,如果與上次保存資訊相同直接返回進行下一次循環

 

device_info = self.update_devices(devices)




# notify plugin about device deltas

 

if device_info:

 

LOG.debug("Agent loop has new devices!")

 

# If treat devices fails - indicates must resync with plugin

 

# 處理增加或刪除設備資訊的主函數 <=== 重要!

 

sync = self.process_network_devices(device_info)

 

devices = device_info['current']




# sleep till end of polling interval

 

elapsed = (time.time() - start)

 

if (elapsed < self.polling_interval):

 

time.sleep(self.polling_interval - elapsed)

 

else:

 

LOG.debug("Loop iteration exceeded interval (%s vs. %s)!",

 

self.polling_interval, elapsed)




以新增設備為例:

 

1. 首先向上層查詢新增設備資訊

 

2. 根據設備的admin_state_up狀態調用LinuxBridge對象方法

 

physical_interface = self.interface_mappings.get(physical_network)

 

if not physical_interface:

 

LOG.error("No mapping for physical network %s" %

 

physical_network)

 

return False




# flat模式

 

if int(vlan_id) == lconst.FLAT_VLAN_ID:

 

self.ensure_flat_bridge(network_id, physical_interface)

 

# vlan模式

 

else:

 

# 為介面添加vlan並創建網橋(如果沒有的話)

 

self.ensure_vlan_bridge(network_id, physical_interface,

 

vlan_id)

 

if utils.execute(['brctl', 'addif', bridge_name, tap_device_name],

 

root_helper=self.root_helper):

 

return False




LOG.debug("Done adding device %s to bridge %s" % (tap_device_name,

 

bridge_name))

 

return True

 

3. 如果是vlan類型網絡

 

def ensure_vlan_bridge(self, network_id, physical_interface, vlan_id):

 

"""Create a vlan and bridge unless they already exist."""

 

interface = self.ensure_vlan(physical_interface, vlan_id)

 

bridge_name = self.get_bridge_name(network_id)

 

self.ensure_bridge(bridge_name, interface)

 

return interface

 

2 消息處理

 

如下圖,在LinuxBridge外掛程式的agent中只接收兩種消息的處理。

664ee604-2326-3858-ab91-4ca927090daa  




一個是刪除network,另一個是更新port。

 

2.1 network_delete

 

def network_delete(self, coNtext, **kwargs):

 

LOG.debug("network_delete received")

 

network_id = kwargs.get('network_id')

 

# 獲取邏輯網絡對應的網橋名稱,前綴"brq"

 

bridge_name = self.linux_br.get_bridge_name(network_id)

 

LOG.debug("Delete %s", bridge_name)

 

self.linux_br.delete_vlan_bridge(bridge_name)

 

def delete_vlan_bridge(self, bridge_name):

 

# 調用命令查詢網橋是否存在

 

if self.device_exists(bridge_name):

 

# 獲取網橋上的所有介面(列舉目錄/sys/devices/virtual/net/${bridge_name}/brif/)

 

interfaces_on_bridge = self.get_interfaces_on_bridge(bridge_name)

 

for interface in interfaces_on_bridge:

 

# 通過命令刪除介面

 

self.remove_interface(bridge_name, interface)

 

for physical_interface in self.interface_mappings.itervalues():

 

# 若是flat類型的網絡

 

if physical_interface == interface:

 

# This is a flat network => return IP's from bridge to

 

# interface

 

ips, gateway = self.get_interface_details(bridge_name)

 

self.update_interface_ip_details(interface,

 

bridge_name,

 

ips, gateway)

 

else:

 

if interface.startswith(physical_interface):

 

# 調用命令刪除介面上創建的vlan

 

self.delete_vlan(interface)




LOG.debug("Deleting bridge %s" % bridge_name)

 

if utils.execute(['ip', 'link', 'set', bridge_name, 'down'],

 

root_helper=self.root_helper):

 

return

 

# 刪除網橋

 

if utils.execute(['brctl', 'delbr', bridge_name],

 

root_helper=self.root_helper):

 

return

 

LOG.debug("Done deleting bridge %s" % bridge_name)




else:

 

LOG.error("Cannot delete bridge %s, does not exist" % bridge_name)

 

2.2 port_update

 

def port_update(self, coNtext, **kwargs):

 

LOG.debug("port_update received")

 

port = kwargs.get('port')

 

# 若操作狀態為True,增加設備

 

if port['admin_state_up']:

 

vlan_id = kwargs.get('vlan_id')

 

# create the networking for the port

 

self.linux_br.add_interface(port['network_id'],

 

vlan_id,

 

port['id'])

 

# 刪除設備

 

else:

 

bridge_name = self.linux_br.get_bridge_name(port['network_id'])

 

tap_device_name = self.linux_br.get_tap_device_name(port['id'])

 

self.linux_br.remove_interface(bridge_name, tap_device_name)
 
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()