Neutron 提供 DHCP 服務的組件是 DHCP agent。 DHCP agent 在網絡節點運行上,默認通過 dnsmasq 實現 DHCP 功能。
配置 DHCP agent
DHCP agent 的配置文件位於 /etc/neutron/dhcp_agent.ini。
dhcp_driver
使用 dnsmasq 實現 DHCP。
interface_driver
使用 linux bridge 連接 DHCP namespace interface。
當創建 network 並在 subnet 上 enable DHCP 時,網絡節點上的 DHCP agent 會啟動一個 dnsmasq 進程為該 network 提供 DHCP 服務。
dnsmasq 是一個提供 DHCP 和 DNS 服務的開源軟件。 dnsmasq 與 network 是一對一關系,一個 dnsmasq 進程可以為同一 netowrk 中所有 enable 了 DHCP 的 subnet 提供服務。
回到我們的實驗環境,之前創建了 flat_net,並且在 subnet 上啟用了 DHCP
DHCP agent 會為每個 network 創建一個目錄 /opt/stack/data/neutron/dhcp/,用於存放該 network 的 dnsmasq 配置文件。
下面討論 dnsmasq 重要的啟動參數:
--dhcp-hostsfile
存放 DHCP host 信息的文件,這里的 host 在我們這里實際上就是 instance。 dnsmasq 從該文件獲取 host 的 IP 與 MAC 的對應關系。 每個 host 對應一個條目,信息來源於 Neutron 數據庫。
對於 flat_net,hostsfile 是 /opt/stack/data/neutron/dhcp/f153b42f-c3a1-4b6c-8865-c09b5b2aa274/host,記錄了 DHCP,cirros-vm1 和 cirros-vm2 的 interface 信息。
--interface
指定提供 DHCP 服務的 interface。 dnsmasq 會在該 interface 上監聽 instance 的 DHCP 請求。
對於 flat_net,interface 是 ns-19a0ed3d-fe。 或許大家還記得,之前我們看到的 DHCP interface 叫 tap19a0ed3d-fe(如下圖所示),並非 ns-19a0ed3d-fe。
從名稱上看,ns-19a0ed3d-fe 和 tap19a0ed3d-fe 應該存在某種聯系,但那是什么呢?
Namespace
Neutron 通過 dnsmasq 提供 DHCP 服務,而 dnsmasq 如何獨立的為每個 network 服務呢?
答案是通過 Linux Network Namespace 隔離
在二層網絡上,VLAN 可以將一個物理交換機分割成幾個獨立的虛擬交換機。 類似地,在三層網絡上,Linux network namespace 可以將一個物理三層網絡分割成幾個獨立的虛擬三層網絡。
每個 namespace 都有自己獨立的網絡棧,包括 route table,firewall rule,network interface device 等。
Neutron 通過 namespace 為每個 network 提供獨立的 DHCP 和路由服務,從而允許租戶創建重疊的網絡。
如果沒有 namespace,網絡就不能重疊,這樣就失去了很多靈活性。
每個 dnsmasq 進程都位於獨立的 namespace, 命名為 qdhcp-<network id>,例如 flat_net,我們有:

ip netns list 命令列出所有的 namespace。
qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 就是 flat_net 的 namespace。
其實,宿主機本身也有一個 namespace,叫 root namespace,擁有所有物理和虛擬 interface device。 物理 interface 只能位於 root namespace。
新創建的 namespace 默認只有一個 loopback device。 管理員可以將虛擬 interface,例如 bridge,tap 等設備添加到某個 namespace。
對於 flat_net 的 DHCP 設備 tap19a0ed3d-fe,需要將其放到 namespace qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 中,但這樣會帶來一個問題: tap19a0ed3d-fe 將無法直接與 root namespace 中的 bridge 設備 brqf153b42f-c3 連接。
Neutron 使用 veth pair 解決了這個問題。
veth pair 是一種成對出現的特殊網絡設備,它們象一根虛擬的網線,可用於連接兩個 namespace。向 veth pair 一端輸入數據,在另一端就能讀到此數據。
tap19a0ed3d-fe 與 ns-19a0ed3d-fe 就是一對 veth pair,它們將 qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 連接到 brqf153b42f-c3。如下圖所示:

可以通過 ip netns exec <network namespace name> <command> 管理 namespace。 例如查看 ns-19a0ed3d-fe 的配置:

以 cirros-vm1 為例分析獲取 DHCP IP 的詳細過程。
在創建 instance 時,Neutron 會為其分配一個 port,里面包含了 MAC 和 IP 地址信息。這些信息會同步更新到 dnsmasq 的 host 文件。如下圖所示:

同時 nova-compute 會設置 cirros-vm1 VIF 的 MAC 地址。

一切准備就緒,instance 獲取 IP 的過程如下:
-
cirros-vm1 開機啟動,發出 DHCPDISCOVER 廣播,該廣播消息在整個 flat_net 中都可以被收到。
-
廣播到達 veth tap19a0ed3d-fe,然后傳送給 veth pair 的另一端 ns-19a0ed3d-fe。dnsmasq 在它上面監聽,dnsmasq 檢查其 host 文件,發現有對應項,於是dnsmasq 以 DHCPOFFER 消息將 IP(172.16.1.103)、子網掩碼(255.255.255.0)、地址租用期限等信息發送給 cirros-vm1。
-
cirros-vm1 發送 DHCPREQUEST 消息確認接受此 DHCPOFFER。
-
dnsmasq 發送確認消息 DHCPACK,整個過程結束。
這個過程我們可以在 dnsmasq 日志中查看。 dnsmasq 默認將日志記錄到 /var/log/syslog。
