SRIOV 簡介
OpenStack 自 Juno 版本開始引入 SRIOV,SRIOV(Single Root I/O Virtualization) 是將 PCIe(PCI) 設備虛擬化成虛擬 PCIe(PCI) 的技術,它最典型的應用是對網卡設備的虛擬化,這裏討論的都是網卡設備的虛擬化。
SRIOV 有兩個重要概念: PF(Physical Function) 和 VF(Virtual Function)。PF 是 host 上的物理實體,VF 則是 PF 虛擬出來的設備。建立 VM 時,VF attach 到 VM 上。對於 VM 來講, VF 和實體 PF 沒有什麼區別。同時,經過 VF 訪問外網不須要通過 OVS(br-int/tap...) 等設備,從而減小了流程,下降了網絡延時。
SRIOV 配置
配置 SRIOV 有兩種方式:
1. 已安裝好的 OpenStack 上配置 SRIOV,須要經過如下幾個步驟:
1) compute node 上建立 VF
2) compute node 上配置 whitelist PCI devices
3) controller node 上配置 neutron-server
4) controller node 上配置 nova-scheduler
5) compute node 上使能 sriov-agent
2. 安裝 OpenStack 的時候在配置文件上配置好 SRIOV 信息:
NovaPCIPassthrough:
- devname: "ens10"
trusted: "true"
physical_network: "sriov-a"
- devname: "ens11"
trusted: "true"
physical_network: "sriov-b"
- devname: "ens20"
trusted: "true"
physical_network: "sriov-a"
- devname: "ens21"
trusted: "true"
physical_network: "sriov-b"
NeutronPhysicalDevMappings: "sriov-a:ens10,sriov-a:ens20,sriov-b:ens10f1,sriov-b:ens21"
physical_network 表示 OpenStack 的 provider network,詳細配置信息可看這裏。
安裝完成以後,登到 compute node 上查看 SRIOV 是否使能:
[root@compute-1 home]# cat /sys/class/net/ens10/device/sriov_
sriov_drivers_autoprobe sriov_offset sriov_totalvfs
sriov_numvfs sriov_stride sriov_vf_device
[root@compute-1 home]# cat /sys/class/net/ens10/device/sriov_numvfs
16
[root@compute-1 home]# cat /sys/class/net/ens10/device/sriov_totalvfs
63
其中,ens10 表示 PF,sriov_numvfs 表示 PF 虛擬出來的 VF 數目,sriov_totalvfs 表示最多可虛擬的 VF 數目。
檢查 VF 是否出於 up 狀態:
[root@compute-1 home]# lspci | grep Eth
09:00.0 Ethernet controller: Intel Corporation 82599 10 Gigabit Dual Port Backplane Connection (rev 01)
09:00.1 Ethernet controller: Intel Corporation 82599 10 Gigabit Dual Port Backplane Connection (rev 01)
09:10.0 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
09:10.1 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
09:10.2 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
...
[root@compute-1 home]# ip link show ens10
4: ens10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 48:df:37:0f:19:f0 brd ff:ff:ff:ff:ff:ff
vf 0 MAC 2e:c7:47:d8:26:ea, spoof checking on, link-state auto, trust off, query_rss off
vf 1 MAC 06:13:09:1d:10:47, spoof checking on, link-state auto, trust off, query_rss off
vf 2 MAC fa:f9:c0:ea:17:79, spoof checking on, link-state auto, trust off, query_rss off
...
建立帶 VF 的 VM
1. 建立網絡
$ openstack network create --provider-physical-network physnet2 \
--provider-network-type vlan --provider-segment 1000 \
sriov-net
$ openstack subnet create --network sriov-net \
--subnet-pool shared-default-subnetpool-v4 \
sriov-subnet
2. 建立 sriov port
$ openstack port create --network $net_id --vnic-type direct \
sriov-port
其中,vnic-type 分別有三種模式:normal, macvtap 和 direct。normal 是 vif 在 OVS 中使用的模式;macvtap 是操做系統虛擬化的網卡,使用 macvtap 模式會將 VF attach 到 macvtap 上;direct 是直接將 VF 分配給 VM 的模式;這裏使用 direct 模式。
查看建立好的 port 屬性:
+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| admin_state_up | UP |
| allowed_address_pairs | |
| binding_host_id | |
| binding_profile | trusted='true' |
| binding_vif_details | |
| binding_vif_type | unbound |
| binding_vnic_type | direct |
| created_at | 2020-06-14T03:10:13Z |
| data_plane_status | None |
| description | |
| device_id | |
| device_owner | |
| dns_assignment | None |
| dns_domain | None |
| dns_name | None |
| extra_dhcp_opts | |
| fixed_ips | ip_address='192.168.2.87', subnet_id='35b2c708-ab7b-4a22-8ae4-d6ecd5e8a5ed' |
| id | 815f26de-ba36-4c9b-b8e2-b052fdb7d28d |
| location | cloud='', project.domain_id=, project.domain_name='Default', project.id='b336e515d511487db8d359e8722c3d7c', project.name='admin', region_name='regionOne', zone= |
| mac_address | fa:16:3e:46:43:be |
| name | sriov-port |
| network_id | 23b60822-b4c7-4501-b509-e9deb92ae925 |
| port_security_enabled | True |
| project_id | b336e515d511487db8d359e8722c3d7c |
| propagate_uplink_status | None |
| qos_policy_id | None |
| resource_request | None |
| revision_number | 1 |
| security_group_ids | 1777fd33-ffd9-404d-b58e-0eb15e0b2c13 |
| status | DOWN |
| tags | |
| trunk_details | None |
| updated_at | 2020-06-14T03:10:13Z |
+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
建立 port 是經過 neutron 組件來完成的,port 在未 attach 到 VM 以前具備較少的屬性,其中,binding_vif_type 表示綁定的 vif 類型,有 HW_VEB, VIF_TYPE_802_QBH 和 VIF_TYPE_802_QBG,vif 是 Virtual Network Interface 的縮寫;binding_host_id 是 nova 根據 port 屬性等調用 nova-scheduler 分配的計算節點。
從 sriov port 能夠看到 mac 地址已經有了,在計算節點經過 ip link show 查看具體是哪一個計算節點分配的 VF:
[root@compute-1 home]# ip link show ens10 | grep fa:16:3e:8b:c6:51
vf 11 MAC fa:16:3e:8b:c6:51, spoof checking on, link-state auto, trust off, query_rss off
能夠看出,port 是 sriov-a(provider network) 中的 ens10 端口虛擬出來的第 11 個 VF。
因爲該 port 是在 computer-1 上的,因此 nova-scheduler 在調度分配計算節點時,其中的 PciPassthroughFilter 會將計算節點選定爲 computer-1。值得注意的一點是 OpenStack 還不支持 attach sriov port 到一個已經存在的節點,猜想可能和這方面有關,即 sriov port 在建立時已經分配好了計算節點,若是 attach 的 VM 不在該計算節點上會出問題。
3. 建立 VM
$ openstack server create --flavor m1.large --image ubuntu_18.04 \
--nic port-id=$port_id \
test-sriov
查看 VM 是否屬於 computer-1:
[root@controller-0 ~]# openstack server show demo | grep compute
| OS-EXT-SRV-ATTR:host | compute-1.localdomain
查看 attach 到 VM 後的 sriov port 屬性:
+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| admin_state_up | UP |
| allowed_address_pairs | |
| binding_host_id | compute-1.localdomain |
| binding_profile | pci_slot='0000:87:13.4', pci_vendor_info='8086:10ed', physical_network='sriov-a' |
| binding_vif_details | connectivity='l2', port_filter='False', vlan='0' |
| binding_vif_type | hw_veb |
| binding_vnic_type | direct |
| created_at | 2020-06-05T01:39:41Z |
| data_plane_status | None |
| description | |
| device_id | 322443ba-91da-472f-88d5-9e300797d457 |
| device_owner | compute:nova |
| dns_assignment | None |
| dns_domain | None |
| dns_name | None |
| extra_dhcp_opts | |
| fixed_ips | ip_address='192.168.2.7', subnet_id='35b2c708-ab7b-4a22-8ae4-d6ecd5e8a5ed' |
| id | cd35f343-774e-4a31-a353-328e2fbad125 |
| location | cloud='', project.domain_id=, project.domain_name='Default', project.id='b336e515d511487db8d359e8722c3d7c', project.name='admin', region_name='regionOne', zone= |
| mac_address | fa:16:3e:46:43:be |
| name | demo-sriov_a |
| network_id | 23b60822-b4c7-4501-b509-e9deb92ae925 |
| port_security_enabled | True |
| project_id | b336e515d511487db8d359e8722c3d7c |
| propagate_uplink_status | None |
| qos_policy_id | None |
| resource_request | None |
| revision_number | 6 |
| security_group_ids | 1777fd33-ffd9-404d-b58e-0eb15e0b2c13 |
| status | ACTIVE |
| tags | |
| trunk_details | None |
| updated_at | 2020-06-05T01:40:21Z |
+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
attach 到 VM 上的 port 的 binding_host_id 肯定爲 compute-1,binding_profile 爲 VF 綁定的 PCI 和 provider 網絡信息,binding_vif_type 爲 hw_veb,hw_veb 表示同一個計算節點和虛擬子網內,不一樣 VM 經過內置網卡的硬件 VEB 將報文環回,不須要經過交換機將報文環回。
在建立 VM 時,涉及到 Nova 和 Neutron 的交互。對於 Nova 來講它並不知道 Neutron 所建立的 port 的屬性信息,使用 --nic 選項使得 nova 從 neutron 處得到 port 的信息。關於 Nova 和 Neutron 的交互可看這裏。
驗證 SRIOV
上圖中,compute1 的 e0 和 e1 網卡分別虛擬出 vf0 和 vf1。e0 的 vf0 被分配給 VM1,在 VM1 上看到的就是 e0 的網卡。e1 的 vf1 被分配給 VM2,在 VM2 上看到的 e0 就是 VM2 的網卡。而且 compute1 上的 e0 和 e1 分別連到交換機上的 1 號和 9 號端口,其中交換機的 50 口爲上連口。構建這個簡單的場景來驗證 SRIOV 是否使能。
具體建立 VM 的方式在上一節已經說了,這裏直接看結果。分別登到 VM1 和 VM2 上查看 VM1 和 VM2 上 e0 網口是否使能:
[root@demo1:/home/robot]
# ip a | grep eth0
18: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 10.57.0.3/27 brd 10.57.0.1 scope global f1om
[root@demo:/home/robot]
# ip a | grep eth0
14: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 10.57.0.2/27 brd 10.57.0.1 scope global f1om
# 從 VM1 ping VM2,在 eth0 端口上抓包:
[root@demo:/home/robot]
# ping -I 10.57.0.2 -c 4 10.57.0.3
PING 10.57.0.3 (10.57.0.3) from 10.57.0.2 : 56(84) bytes of data.
64 bytes from 10.57.0.3: icmp_seq=1 ttl=64 time=0.383 ms
64 bytes from 10.57.0.3: icmp_seq=2 ttl=64 time=0.103 ms
64 bytes from 10.57.0.3: icmp_seq=3 ttl=64 time=0.274 ms
64 bytes from 10.57.0.3: icmp_seq=4 ttl=64 time=0.146 ms
--- 10.57.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3089ms
[root@demo1:/home/robot]
# tcpdump -i f1om host 10.57.0.2 -nn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on f1om, link-type EN10MB (Ethernet), capture size 262144 bytes
22:51:48.904493 ARP, Request who-has 10.57.199.65 tell 10.57.0.2, length 42
22:51:49.146108 IP 10.57.0.3 > 10.57.0.2: ICMP echo reply, id 15, seq 1, length 64
22:51:50.187253 IP 10.57.0.3 > 10.57.0.2: ICMP echo reply, id 15, seq 2, length 64
22:51:51.211443 IP 10.57.0.3 > 10.57.0.2: ICMP echo reply, id 15, seq 3, length 64
22:51:52.235339 IP 10.57.0.3 > 10.57.0.2: ICMP echo reply, id 15, seq 4, length 64
22:51:54.453779 ARP, Request who-has 10.57.0.2 tell 10.57.0.3, length 28
22:51:54.453885 ARP, Reply 10.57.0.2 is-at fa:16:3e:46:43:be, length 42
22:51:54.475245 ARP, Request who-has 10.57.0.3 tell 10.57.0.2, length 42
22:51:54.475260 ARP, Reply 10.57.0.3 is-at fa:16:3e:d6:f0:b6, length 28
22:51:58.917049 ARP, Request who-has 10.57.199.65 tell 10.57.0.2, length 42
22:52:08.936950 ARP, Request who-has 10.57.199.65 tell 10.57.0.2, length 42
從 VM1 能夠 ping 通 VM2,SRIOV 使能。
Trust mode
如今結束 SRIOV 還爲時尚早,再介紹個 SRIOV 中值得關注的參數 Trust mode。與其它網口輸出的信息不太相同的是 vf 的輸出有個 trust off 參數:
[root@compute-1 home]# ip link show ens10 | grep fa:16:3e:8b:c6:51
vf 11 MAC fa:16:3e:8b:c6:51, spoof checking on, link-state auto, trust off, query_rss off
它相似於硬件網卡的混雜模式,在建立 VM 的時候可指定將 trust 設爲 on,即 vf 將進入 trust on 模式,進入該模式以後 VM 能夠作一些特權操做,好比進入混雜模式和修改網卡的 mac 地址等。
關於 Trust mode 的介紹可看這裏和這裏。
要開啓 trust mode on 模式,首先須要在 host 上將 vf trust mode 置成 on,參看這裏可在安裝的配置 trust mode 爲 on,也可手動經過命令將 trust mode 設爲 on:
$ ip link set ens10 vf 19 trust on
而後,在建立 port 的時候將 port 的 binding:profile 屬性設爲 trusted(經過 heat 建立 trust mode 能夠在 heat template 的 OS::Neutron::port 類型下的 value_specs 裏指定 trust mode 參數,詳細信息看這裏):
openstack port create --network sriov111 \
--vnic-type direct --binding-profile trusted=true \
sriov111_port_trusted
最後,建立 VM 時 port 被 attach 到 VM 上,使得 VM 內的網口處於 trust on 模式:
可經過命令 /sys/class/net/<eth>/flags 檢查網卡是否出於混雜模式(這是硬件上的配置,VM 上還須要 check):
[root@controller-0 ~]# cat /sys/class/net/ens10/flags
0x1003
[root@controller-0 ~]# ifconfig ens10 promisc
[root@controller-0 ~]# cat /sys/class/net/ens10/flags
0x1103
注意,trust 模式僅在 Rocky 的 release 版本及以後版本才支持,這裏詳細介紹了使能 trust mode 後的效果。
(完)