前天我們已經建立了一個logical switch, 並驗證二組veth pair是能透過logical switch連通。我們在建立這二組veth pair時,我們是採用static IP,所以在veth一端所在的namespace裡,可以查到所指定的IP。OVN也支援透過DHCP動態分配IP給namespace。要完成動態分配IP,在namespace並不需要做什麼特別的事,只要如同往常一般,透過DHCP client取得IP即可;但是,在logical switch上,則必需加以設定。今天,就讓我們來理解OVN的logical swicth是如何支援DHCP吧
先讓我們來看一下今天想要完成的設定,與昨天的區別在那裡吧。今天的範例要使用DHCP的話,與昨天的差別主要在二個地方:
other_config:subnet
,指定DHCP所要使用的subnetdynamic
;以及要指定要使用的dhcp-options
這裡的dhcp-options
指向的是一個事先透過ovn-nbctl
建立的一個dhcp-options
物件,而這個物件主要的作用是用來描述要使用的dhcp 服務的屬性。我們可以用ovn-nbctl create dhcp_options
建立。
例如: 建立一個subnet是10.0.0.0/24,gateway是10.0.0.1的dhcp
ovn-nbctl create dhcp_options \
cidr=10.0.0.0/24 \
options='"lease_time"="3600" "router"="10.0.0.1" "server_id"="10.0.0.1" "server_mac"="c0:ff:ee:00:00:01"'
也可以透過 ovn-nbctl list dhcp-options
查看,以及 ovn-nbctl destroy dhcp-options <id>
刪除。
有了基本的認識後,再來看一下整個範例的過程吧
和昨天的差別,建立namespace,不指定使用的IP, 稍等會用dhcp分配IP
git clone https://github.com/ogre0403/iTHome-2023.git
sudo su
cd /opt/iTHome-2023/day-03
source helper.sh
create-ns ns1
create-ns ns2
建立一個subnet是 10.0.0.0/24
,gateway是10.0.0.1
的dhcp-options。再將代表這個dhcp-options的uuid,用來建立logical switch。
uuid=$(create-dhcp-options 10.0.0.0/24 10.0.0.1)
create-ovn-ls-and-lsp ls0 $uuid 10.0.0.0/24
assign-iface-to-ovn-lsp ls0
如果深入去看 今天和昨天使用的
create-ovn-ls-and-lsp
,就可以發現,基本上都是相同的,差別只在於每個要用dhcp的port, 要將address設為dynamic
, 以及要指定dhcp-options的uuid.
最後,分別在ns1與ns2 裡,用dhclient 取得IP後,再試看看二個namespace是否能夠互連。
ip netns exec ns1 dhclient
ip netns exec ns1 ip a
ip netns exec ns2 dhclient
ip netns exec ns2 ip a
在一般的區域網路裡,要透過DHCP分配IP,需要有DHCP server處理DHCP client發出的 dhcp request。但我們到目前也沒有安裝DHCP server, OVN 是如何透過DHCP分配IP呢? OVN所使用的DHCP server又在那裡呢? 讓我們來進一步了解OVN的DHCP流程吧。
OVN 提供ovn-trace 了一個工具,可以用於模擬和跟踪虛擬網絡中的封包的路徑。我們使用ovn-trace來追蹤一個namespace發出的dhcp request,會得到怎樣的結果。
NS=ns1
NS_MAC=$(ip netns exec $NS ip link show eth0 |grep link/ether | awk '{print $2}')
LS=ls0
ovn-trace $LS "
inport==\"$LS-$NS\" &&
eth.src==$NS_MAC &&
ip4.src==0.0.0.0 &&
ip.ttl==1 &&
ip4.dst==255.255.255.255 &&
udp.src==68 &&
udp.dst==67"
ingress(dp="net0", inport="port2")
----------------------------------
...
14. ls_in_dhcp_options (ovn-northd.c:6426): inport == "ls0-ns1" && eth.src == de:8a:77:8e:ca:db && ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67, priority 100, uuid 9eb9c08d
reg0[3] = put_dhcp_opts(offerip = 10.0.0.3, lease_time = 3600, netmask = 255.255.255.0, router = 10.0.0.1, server_id = 10.0.0.1);
/* We assume that this packet is DHCPDISCOVER or DHCPREQUEST. */
next;
15. ls_in_dhcp_response (ovn-northd.c:6474): inport == "ls0-ns1" && eth.src == de:8a:77:8e:ca:db && ip4 && udp.src == 68 && udp.dst == 67 && reg0[3], priority 100, uuid 87c28faa
eth.dst = eth.src;
eth.src = 02:00:f2:99:cf:f8;
ip4.src = 10.0.0.1;
udp.src = 67;
udp.dst = 68;
outport = inport;
flags.loopback = 1;
output;
egress(dp="ls0", inport="ls0-ns1", outport="ls0-ns1")
-----------------------------------------------------
4. ls_out_acl (ovn-northd.c:5401): outport == "ls0-ns1" && eth.src == 02:00:f2:99:cf:f8 && ip4.src == 10.0.0.1 && udp && udp.src == 67 && udp.dst == 68, priority 34000, uuid 30ef0e29
next;
9. ls_out_port_sec_l2 (ovn-northd.c:4613): outport == "ls0-ns1", priority 50, uuid 014a78b3
output;
/* output to "ls0-ns1", type "" */
從ovn-trace的結果,我們可以看到
由這個流程可以得知OVN在實作DHCP時,namesapce送出的dhcp request,並沒有被任何傳統意義上的DHCP server處理,完全由 hypervisor上的ovn-controller 在收到dhcp request 後,分配一個IP後,就馬上由原來的port送回去給namespace。
從昨天到今天為止,目前我們已經完成了二個OVN的實驗,二個實驗都是在logical switch上,讓二個namespace互通,只是昨天是用static ip,而今天是用DHCP取得IP。也知道建立出來的邏輯交換器的長像以及相對應在主機的br-int上的interafce為何。但OVN到底是如何知道logical switch上的port,是對應至那一個hypervisor上的br-int的那一個interface呢? 如果沒有這種資訊,OVN不太可能知道br-int上收到封包後,要往那一個目的端發送。
讓我們深入看一下 helper.sh
裡的create-ovn-ls-and-lsp
& assign-iface-to-ovn-lsp
,下面是將這個二個function裡用的for loop 展開後的一個例子。
# create-ovn-ls-and-lsp ls0
ovn-nbctl ls-add ls0
ovn-nbctl lsp-add ls0 ls0-ns1
ovn-nbctl lsp-set-addresses ls0-ns1 e6:3c:39:39:3d:f4
ovn-nbctl lsp-add ls0 ls0-ns2
ovn-nbctl lsp-set-addresses ls0-ns2 d6:ba:2e:b8:65:da
# assign-iface-to-ovn-lsp ls0
ovs-vsctl add-port br-int veth-ns1-br
ovs-vsctl set Interface veth-ns1-br external_ids:iface-id=ls0-ns1
ovs-vsctl add-port br-int veth-ns2-br
ovs-vsctl set Interface veth-ns2-br external_ids:iface-id=ls0-ns2
可以看到create-ovn-ls-and-lsp
的function裡, 是透過ovn-nbctl建立logical switch上的logical port之後;還必需再使用ovs-vsctl將hypervisor的br-int的某一個interface與logical switch的logical port做綁定,即 ovs-vsctl set Interface veth-ns1-br external_ids:iface-id=ls0-ns1
這一行所在做的事;這就是代表圖中的controller和logical switch的那二個綠色鍵頭。