女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

DPDK的提出以及設(shè)計(jì)思想是什么?

Linux閱碼場(chǎng) ? 來源:Linux閱碼場(chǎng) ? 作者:孫雷 ? 2021-05-24 17:29 ? 次閱讀

01

vhost-user

DPDK的提出以及設(shè)計(jì)思想

隨著各種互聯(lián)網(wǎng)應(yīng)用的不斷出現(xiàn),網(wǎng)絡(luò)設(shè)備以及服務(wù)器的帶寬也快速提升,從千兆到萬兆再到25G,40G,100G快速演變。

與此同時(shí),在云計(jì)算和系統(tǒng)虛擬化技術(shù)的快速發(fā)展的推動(dòng)下,虛擬機(jī)的網(wǎng)絡(luò)處理能力需求也逐年增強(qiáng)。

另外,不僅是在服務(wù)器領(lǐng)域,很多網(wǎng)絡(luò)服務(wù)也都逐漸向虛擬化,資源池化,云化的方向發(fā)展,比如路由器,交換機(jī),防火墻,基站等常用網(wǎng)絡(luò)設(shè)備原本都是硬件解決方案,現(xiàn)在也逐漸向虛擬化方向發(fā)展,業(yè)界急需適合高性能網(wǎng)絡(luò)的軟件解決方案。

既往的基于Linux實(shí)現(xiàn)的網(wǎng)絡(luò)服務(wù)是基于內(nèi)核的,也就是說所有數(shù)據(jù)包的發(fā)送和接收都要經(jīng)過內(nèi)核協(xié)議棧。在處理大流量和高并發(fā)的情況下,頻繁的硬件中斷會(huì)降低內(nèi)核數(shù)據(jù)包的處理能力,同時(shí)內(nèi)核空間和用戶空間之間的數(shù)據(jù)拷貝也會(huì)產(chǎn)生比較大的負(fù)載。

為了進(jìn)一步提升網(wǎng)絡(luò)數(shù)據(jù)處理能力,Linux UIO (user-space drivers)技術(shù)把硬件操作映射到用戶空間,實(shí)現(xiàn)了在用戶空間直接操作網(wǎng)卡硬件。

這樣網(wǎng)絡(luò)數(shù)據(jù)包的處理就可以不經(jīng)過Linux內(nèi)核了,避免了高速網(wǎng)絡(luò)數(shù)據(jù)處理時(shí)內(nèi)核中斷爆炸和大量數(shù)據(jù)復(fù)制的問題,進(jìn)而讓網(wǎng)絡(luò)處理能力得以大幅度的提升。

繞過內(nèi)核直接在用戶態(tài)處理網(wǎng)絡(luò)數(shù)據(jù)包,不僅可以解決內(nèi)核的性能瓶頸,而且還易于開發(fā)和維護(hù),和基于內(nèi)核模塊的實(shí)現(xiàn)相比也更靈活。

另外,因?yàn)槌绦蜻\(yùn)行在用戶空間,即使有問題也不影響Linux內(nèi)核和系統(tǒng)的其他模塊,也增強(qiáng)了整個(gè)系統(tǒng)的可用性。

針對(duì)高性能網(wǎng)絡(luò)軟件開發(fā)框架的需求,基于Linux UIO技術(shù)在應(yīng)用層處理網(wǎng)絡(luò)數(shù)據(jù)包,這也正是IntelDPDK的主要設(shè)計(jì)思想。

DPDK應(yīng)用初識(shí)

678ed02a-bc29-11eb-bf61-12bb97331649.png

圖1Linux內(nèi)核處理路徑(慢路徑)和DPDK處理路徑(快路徑)對(duì)比

如圖1所表示的就是基于Linux內(nèi)核的數(shù)據(jù)處理路徑(慢路徑)和基于DPDK的用戶空間數(shù)據(jù)處理路徑(快路徑)的對(duì)比。

這里需要特別說明的是,Intel DPDK被編譯之后其實(shí)是一系列的庫文件,供應(yīng)用程序調(diào)用和鏈接。基于DPDK機(jī)制開發(fā)的應(yīng)用程序在編譯和鏈接DPDK的庫文件之后,就可以進(jìn)行高速的網(wǎng)絡(luò)處理了。

這些DPDK應(yīng)用都是運(yùn)行在用戶空間的應(yīng)用程序。通過Linux UIO的機(jī)制以及少量?jī)?nèi)核模塊(例如Intel x86平臺(tái)上需要預(yù)先加載igb_uio等內(nèi)核驅(qū)動(dòng)模塊),這些運(yùn)行在用戶空間的DPDK應(yīng)用程序能夠旁路Linux內(nèi)核,直接操作物理網(wǎng)卡進(jìn)而完成高速網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送和接收。

截止到目前為止DPDK已經(jīng)支持多種硬件體系結(jié)構(gòu),包括Intel x86,ARM,PowerPC等等,并且被網(wǎng)絡(luò)設(shè)備廠商和互聯(lián)網(wǎng)廠商廣泛接受,已經(jīng)有很多基于DPDK開發(fā)的產(chǎn)品和服務(wù)投入到生產(chǎn)環(huán)境使用了。

IntelDPDK的核心技術(shù)之一是PMD (用戶態(tài)的輪詢模式驅(qū)動(dòng))。通過非中斷以及數(shù)據(jù)進(jìn)出應(yīng)用緩沖區(qū)內(nèi)存的零拷貝機(jī)制,進(jìn)一步提高發(fā)送接受數(shù)據(jù)的效率。用戶態(tài)模式的PMD驅(qū)動(dòng),去除中斷,避免內(nèi)核態(tài)和用戶態(tài)內(nèi)存拷貝,減少系統(tǒng)開銷,從而提升I/O吞吐能力。

我們可以通過分析DPDK中的L2fw程序,大致了解一下DPDK應(yīng)用程序的基本結(jié)構(gòu)。

具體的代碼可以參考dpdk-stable-18.11.11/examples/l2fwd/main.c。l2fwd是一個(gè)簡(jiǎn)單的DPDK應(yīng)用程序,可以看出在main函數(shù)中,調(diào)用rte_eal_init函數(shù)對(duì)DPDK運(yùn)行環(huán)境進(jìn)行初始化之后,調(diào)用l2fwd_launch_one_lcore函數(shù)在每個(gè)CPU的核上都運(yùn)行l(wèi)2fwd_main_loop函數(shù)。

l2fwd_main_loop函數(shù)就是在無限循環(huán)中不斷的輪詢?cè)揅PU核綁定的網(wǎng)卡的所有端口,調(diào)用rte_eth_tx_buffer_flush和rte_eth_rx_burst進(jìn)行數(shù)據(jù)包的發(fā)送和接收,進(jìn)而再完成轉(zhuǎn)發(fā)。

被DPDK應(yīng)用綁定的CPU核不再被Linux內(nèi)核調(diào)度,而是被l2fwd_main_loop函數(shù)獨(dú)占。所以和原來基于Linux內(nèi)核的實(shí)現(xiàn)相比,網(wǎng)絡(luò)數(shù)據(jù)包的處理能力得以大幅度提升。 DPDK中的PMD技術(shù)的具體實(shí)現(xiàn),可以參考dpdk-stable-18.11.11/drivers/net/e1000/igb_ethdev.c中的函數(shù)eth_igb_dev_init,PMD相關(guān)的實(shí)現(xiàn)是DPDK的內(nèi)部實(shí)現(xiàn),限于篇幅,我們這里就不展開講解了。

int
main(intargc,char**argv)
{
……
/*initEAL*/
ret=rte_eal_init(argc,argv);
if(ret ……
/*launchper-lcoreinitoneverylcore*/
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore,NULL,CALL_MASTER);
……
}
staticint
l2fwd_launch_one_lcore(__attribute__((unused))void*dummy)
{
l2fwd_main_loop();
return0;
}
/*mainprocessingloop*/
staticvoid
l2fwd_main_loop(void)
{
structrte_mbuf*pkts_burst[MAX_PKT_BURST];
structrte_mbuf*m;
intsent;
unsignedlcore_id;
uint64_tprev_tsc,diff_tsc,cur_tsc,timer_tsc;
unsignedi,j,portid,nb_rx;
structlcore_queue_conf*qconf;
constuint64_tdrain_tsc=(rte_get_tsc_hz()+US_PER_S-1)/US_PER_S*
BURST_TX_DRAIN_US;
structrte_eth_dev_tx_buffer*buffer;
prev_tsc=0;
timer_tsc=0;
lcore_id=rte_lcore_id();
qconf=&lcore_queue_conf[lcore_id];
if(qconf->n_rx_port==0){
RTE_LOG(INFO,L2FWD,"lcore%uhasnothingtodo ",lcore_id);
return;
}
RTE_LOG(INFO,L2FWD,"enteringmainlooponlcore%u ",lcore_id);
for(i=0;in_rx_port;i++){
portid=qconf->rx_port_list[i];
RTE_LOG(INFO,L2FWD,"--lcoreid=%uportid=%u ",lcore_id,
portid);
}
while(!force_quit){
cur_tsc=rte_rdtsc();
/*
*TXburstqueuedrain
*/
diff_tsc=cur_tsc-prev_tsc;
if(unlikely(diff_tsc>drain_tsc)){
for(i=0;in_rx_port;i++){
portid=l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer=tx_buffer[portid];
sent=rte_eth_tx_buffer_flush(portid,0,buffer);
if(sent)
port_statistics[portid].tx+=sent;
}
/*iftimerisenabled*/
if(timer_period>0){
/*advancethetimer*/
timer_tsc+=diff_tsc;
/*iftimerhasreacheditstimeout*/
if(unlikely(timer_tsc>=timer_period)){
/*dothisonlyonmastercore*/
if(lcore_id==rte_get_master_lcore()){
print_stats();
/*resetthetimer*/
timer_tsc=0;
}
}
}
prev_tsc=cur_tsc;
}
/*
*ReadpacketfromRXqueues
*/
for(i=0;in_rx_port;i++){
portid=qconf->rx_port_list[i];
nb_rx=rte_eth_rx_burst(portid,0,
pkts_burst,MAX_PKT_BURST);
port_statistics[portid].rx+=nb_rx;
for(j=0;j m=pkts_burst[j];
rte_prefetch0(rte_pktmbuf_mtod(m,void*));
l2fwd_simple_forward(m,portid);
}
}
}
}

vhost-user與DPDK

在對(duì)DPDK應(yīng)用程序有了一個(gè)基本認(rèn)識(shí),并理解了基本原理和核心技術(shù)的基礎(chǔ)上,下面我們進(jìn)入到DPDK場(chǎng)景下用戶態(tài)的virtio-net的實(shí)現(xiàn),也就是vhost-user的相關(guān)介紹。

DPDK場(chǎng)景下,virtio-net后端和virtio-net前端的關(guān)系圖,其中涉及到OVS-DPDK,QEMU,Linux內(nèi)核和物理網(wǎng)卡硬件。我們接下來會(huì)先講一下各個(gè)模塊之間的關(guān)系,以及它們和virtio-net前端和后端的關(guān)系。

-OVS-DPDK:實(shí)現(xiàn)了三部分功能。1). 用戶空間的PMD,不斷地和物理網(wǎng)卡通信,發(fā)送接收數(shù)據(jù)包;2). 虛擬交換機(jī)的功能,這部分和我們平時(shí)熟悉的OVS是一樣的;3). DPDK場(chǎng)景下的virtio-net后端的實(shí)現(xiàn),和virtio-net前端通信。

-QEMU:是一個(gè)運(yùn)行在用戶空間的多線程程序,有運(yùn)行虛擬機(jī)的vCPU線程,有處理中斷的KVM線程和eventfd。不同之處在于:在DPDK場(chǎng)景下,virtio-net前端是運(yùn)行在虛擬機(jī)線程內(nèi)的DPDK應(yīng)用程序。這時(shí),虛擬機(jī)的網(wǎng)絡(luò)接口的類型是vhost-user,它會(huì)基于UNIX domain socket和virtio-net后端(實(shí)現(xiàn)在OVS-DPDK中)通信。

可以看出,在DPDK場(chǎng)景下,virtio-net前端和后端的實(shí)現(xiàn)都在DPDK代碼中。

在運(yùn)行態(tài)的時(shí)候,就像圖2所顯示的那樣,virtio-net前端是QEMU虛擬機(jī)內(nèi)運(yùn)行的DPDK應(yīng)用程序,virtio-net后端運(yùn)行在OVS-DPDK中。

兩者都運(yùn)行在用戶態(tài),通過UNIX domain socket進(jìn)行通信。vhost-user是將virtio-net驅(qū)動(dòng)在用戶態(tài)的實(shí)現(xiàn)。

下面我們結(jié)合結(jié)合DPDK 18.11的代碼,針對(duì)virtio設(shè)備的初始化,發(fā)送數(shù)據(jù)的處理流程,做進(jìn)一步的分析和講解。

設(shè)備發(fā)現(xiàn)和初始化

在QEMU虛擬機(jī)中運(yùn)行DPDK應(yīng)用時(shí):virtio-net前端的初始化的具體實(shí)現(xiàn)是在dpdk-stable-18.11.11/drivers/net/virtio/virtio_ethdev.c文件中,其中rte_virtio_pmd是驅(qū)動(dòng)的主要數(shù)據(jù)結(jié)構(gòu)。

QEMU中的虛擬機(jī)運(yùn)行DPDK應(yīng)用程序的時(shí)候,在指定vhost-user端口的時(shí)候,會(huì)注冊(cè)rte_virtio_pmd驅(qū)動(dòng)程序。驅(qū)動(dòng)中的probe函數(shù)注冊(cè)為eth_virtio_pci_probe函數(shù)。DPDK驅(qū)動(dòng)程序這樣的寫法和Linux內(nèi)核中的PCI網(wǎng)絡(luò)驅(qū)動(dòng)是一樣的,比較容易理解。

函數(shù)eth_virtio_dev_init會(huì)調(diào)用virtio_init_device函數(shù),其中可以看到我們之前介紹過的復(fù)合virtio規(guī)范的協(xié)商特性位(feature bits),配置MTU等網(wǎng)卡相關(guān)的配置,調(diào)用virtio_alloc_queues配置虛擬隊(duì)列等操作。

staticstructrte_pci_driverrte_virtio_pmd={
.driver={
.name="net_virtio",
},
.id_table=pci_id_virtio_map,
.drv_flags=0,
.probe=eth_virtio_pci_probe,
.remove=eth_virtio_pci_remove,
};
RTE_INIT(rte_virtio_pmd_init)
{
rte_eal_iopl_init();
rte_pci_register(&rte_virtio_pmd);
}
staticinteth_virtio_pci_probe(structrte_pci_driver*pci_drv__rte_unused,
structrte_pci_device*pci_dev)
{
if(rte_eal_iopl_init()!=0){
PMD_INIT_LOG(ERR,"IOPLcallfailed-cannotusevirtioPMD");
return1;
}
/*virtiopmdskipsprobeifdeviceneedstoworkinvdpamode*/
if(vdpa_mode_selected(pci_dev->device.devargs))
return1;
returnrte_eth_dev_pci_generic_probe(pci_dev,sizeof(structvirtio_hw),eth_virtio_dev_init);
}
/*resetdeviceandrenegotiatefeaturesifneeded*/
staticint
virtio_init_device(structrte_eth_dev*eth_dev,uint64_treq_features)
{
structvirtio_hw*hw=eth_dev->data->dev_private;
structvirtio_net_config*config;
structvirtio_net_configlocal_config;
structrte_pci_device*pci_dev=NULL;
intret;
/*Resetthedevicealthoughnotnecessaryatstartup*/
vtpci_reset(hw);
if(hw->vqs){
virtio_dev_free_mbufs(eth_dev);
virtio_free_queues(hw);
}
/*Tellthehostwe'venoticedthisdevice.*/
vtpci_set_status(hw,VIRTIO_CONFIG_STATUS_ACK);
/*Tellthehostwe'veknownhowtodrivethedevice.*/
vtpci_set_status(hw,VIRTIO_CONFIG_STATUS_DRIVER);
if(virtio_negotiate_features(hw,req_features) return-1;
if(!hw->virtio_user_dev){
pci_dev=RTE_ETH_DEV_TO_PCI(eth_dev);
rte_eth_copy_pci_info(eth_dev,pci_dev);
}
/*IfhostdoesnotsupportbothstatusandMSI-XthendisableLSC*/
if(vtpci_with_feature(hw,VIRTIO_NET_F_STATUS)&&
hw->use_msix!=VIRTIO_MSIX_NONE)
eth_dev->data->dev_flags|=RTE_ETH_DEV_INTR_LSC;
else
eth_dev->data->dev_flags&=~RTE_ETH_DEV_INTR_LSC;
/*Settinguprx_headersizeforthedevice*/
if(vtpci_with_feature(hw,VIRTIO_NET_F_MRG_RXBUF)||
vtpci_with_feature(hw,VIRTIO_F_VERSION_1))
hw->vtnet_hdr_size=sizeof(structvirtio_net_hdr_mrg_rxbuf);
else
hw->vtnet_hdr_size=sizeof(structvirtio_net_hdr);
/*CopythepermanentMACaddressto:virtio_hw*/
virtio_get_hwaddr(hw);
ether_addr_copy((structether_addr*)hw->mac_addr,
ð_dev->data->mac_addrs[0]);
PMD_INIT_LOG(DEBUG,
"PORTMAC:%02X:%02X:%02X:%02X:%02X:%02X",
hw->mac_addr[0],hw->mac_addr[1],hw->mac_addr[2],
hw->mac_addr[3],hw->mac_addr[4],hw->mac_addr[5]);
if(vtpci_with_feature(hw,VIRTIO_NET_F_CTRL_VQ)){
config=&local_config;
vtpci_read_dev_config(hw,
offsetof(structvirtio_net_config,mac),
&config->mac,sizeof(config->mac));
if(vtpci_with_feature(hw,VIRTIO_NET_F_STATUS)){
vtpci_read_dev_config(hw,
offsetof(structvirtio_net_config,status),
&config->status,sizeof(config->status));
}else{
PMD_INIT_LOG(DEBUG,
"VIRTIO_NET_F_STATUSisnotsupported");
config->status=0;
}
if(vtpci_with_feature(hw,VIRTIO_NET_F_MQ)){
vtpci_read_dev_config(hw,
offsetof(structvirtio_net_config,max_virtqueue_pairs),
&config->max_virtqueue_pairs,
sizeof(config->max_virtqueue_pairs));
}else{
PMD_INIT_LOG(DEBUG,
"VIRTIO_NET_F_MQisnotsupported");
config->max_virtqueue_pairs=1;
}
hw->max_queue_pairs=config->max_virtqueue_pairs;
if(vtpci_with_feature(hw,VIRTIO_NET_F_MTU)){
vtpci_read_dev_config(hw,
offsetof(structvirtio_net_config,mtu),
&config->mtu,
sizeof(config->mtu));
/*
*MTUvaluehasalreadybeencheckedatnegotiation
*time,butcheckagainincaseithaschangedsince
*then,whichshouldnothappen.
*/
if(config->mtu PMD_INIT_LOG(ERR,"invalidmaxMTUvalue(%u)",
config->mtu);
return-1;
}
hw->max_mtu=config->mtu;
/*SetinitialMTUtomaximumonesupportedbyvhost*/
eth_dev->data->mtu=config->mtu;
}else{
hw->max_mtu=VIRTIO_MAX_RX_PKTLEN-ETHER_HDR_LEN-
VLAN_TAG_LEN-hw->vtnet_hdr_size;
}
PMD_INIT_LOG(DEBUG,"config->max_virtqueue_pairs=%d",
config->max_virtqueue_pairs);
PMD_INIT_LOG(DEBUG,"config->status=%d",config->status);
PMD_INIT_LOG(DEBUG,
"PORTMAC:%02X:%02X:%02X:%02X:%02X:%02X",
config->mac[0],config->mac[1],
config->mac[2],config->mac[3],
config->mac[4],config->mac[5]);
}else{
PMD_INIT_LOG(DEBUG,"config->max_virtqueue_pairs=1");
hw->max_queue_pairs=1;
hw->max_mtu=VIRTIO_MAX_RX_PKTLEN-ETHER_HDR_LEN-
VLAN_TAG_LEN-hw->vtnet_hdr_size;
}
ret=virtio_alloc_queues(eth_dev);
if(ret returnret;
if(eth_dev->data->dev_conf.intr_conf.rxq){
if(virtio_configure_intr(eth_dev) PMD_INIT_LOG(ERR,"failedtoconfigureinterrupt");
virtio_free_queues(hw);
return-1;
}
}
vtpci_reinit_complete(hw);
if(pci_dev)
PMD_INIT_LOG(DEBUG,"port%dvendorID=0x%xdeviceID=0x%x",
eth_dev->data->port_id,pci_dev->id.vendor_id,
pci_dev->id.device_id);
return0;
}

在OVS-DPDK中添加一個(gè)vhost-user網(wǎng)絡(luò)接口時(shí):OVS-DPDK會(huì)調(diào)用rte_vhost_driver_register函數(shù),首先根據(jù)傳入?yún)?shù)path文件路徑創(chuàng)建UNIX domain socket,用于后續(xù)virtio-net前端(QEMU虛擬機(jī)中的DPDK應(yīng)用程序)和virtio-net后端(OVS-DPDK應(yīng)用程序)的通信。

這部分相關(guān)的源碼在dpdk-stable-18.11.11/lib/librte_vhost/socket.c的第824行,主要的函數(shù)是rte_vhost_driver_register。

/*
*Registeranewvhost-usersocket;herewecouldactasserver
*(thedefaultcase),orclient(whenRTE_VHOST_USER_CLIENT)flag
*isset.
*/
int
rte_vhost_driver_register(constchar*path,uint64_tflags)
{
intret=-1;
structvhost_user_socket*vsocket;
if(!path)
return-1;
pthread_mutex_lock(&vhost_user.mutex);
if(vhost_user.vsocket_cnt==MAX_VHOST_SOCKET){
RTE_LOG(ERR,VHOST_CONFIG,
"error:thenumberofvhostsocketsreachesmaximum ");
gotoout;
}
vsocket=malloc(sizeof(structvhost_user_socket));
if(!vsocket)
gotoout;
memset(vsocket,0,sizeof(structvhost_user_socket));
vsocket->path=strdup(path);
if(vsocket->path==NULL){
RTE_LOG(ERR,VHOST_CONFIG,
"error:failedtocopysocketpathstring ");
vhost_user_socket_mem_free(vsocket);
gotoout;
}
TAILQ_INIT(&vsocket->conn_list);
ret=pthread_mutex_init(&vsocket->conn_mutex,NULL);
if(ret){
RTE_LOG(ERR,VHOST_CONFIG,
"error:failedtoinitconnectionmutex ");
gotoout_free;
}
vsocket->vdpa_dev_id=-1;
vsocket->dequeue_zero_copy=flags&RTE_VHOST_USER_DEQUEUE_ZERO_COPY;
if(vsocket->dequeue_zero_copy&&
(flags&RTE_VHOST_USER_IOMMU_SUPPORT)){
RTE_LOG(ERR,VHOST_CONFIG,
"error:enablingdequeuezerocopyandIOMMUfeatures"
"simultaneouslyisnotsupported ");
gotoout_mutex;
}
/*
*Setthesupportedfeaturescorrectlyforthebuiltinvhost-user
*netdriver.
*
*Applicationsknownothingaboutfeaturesthebuiltinvirtionet
*driver(virtio_net.c)supports,thusit'snotpossibleforthem
*toinvokerte_vhost_driver_set_features().Toworkaroundit,here
*wesetitunconditionally.Iftheapplicationwanttoimplement
*anothervhost-userdriver(saySCSI),itshouldcallthe
*rte_vhost_driver_set_features(),whichwilloverwritefollowing
*twovalues.
*/
vsocket->use_builtin_virtio_net=true;
vsocket->supported_features=VIRTIO_NET_SUPPORTED_FEATURES;
vsocket->features=VIRTIO_NET_SUPPORTED_FEATURES;
vsocket->protocol_features=VHOST_USER_PROTOCOL_FEATURES;
/*
*Dequeuezerocopycan'tassuredescriptorsreturnedinorder.
*Also,itrequiresthattheguestmemoryispopulated,whichis
*notcompatiblewithpostcopy.
*/
if(vsocket->dequeue_zero_copy){
if((flags&RTE_VHOST_USER_CLIENT)!=0)
RTE_LOG(WARNING,VHOST_CONFIG,
"zerocopymaybeincompatiblewithvhostclientmode ");
vsocket->supported_features&=~(1ULL< vsocket->features&=~(1ULL< RTE_LOG(INFO,VHOST_CONFIG,
"Dequeuezerocopyrequested,disablingpostcopysupport ");
vsocket->protocol_features&=
~(1ULL< }
if(!(flags&RTE_VHOST_USER_IOMMU_SUPPORT)){
vsocket->supported_features&=~(1ULL< vsocket->features&=~(1ULL< }
if(!(flags&RTE_VHOST_USER_POSTCOPY_SUPPORT)){
vsocket->protocol_features&=
~(1ULL< }else{
}
if((flags&RTE_VHOST_USER_CLIENT)!=0){
vsocket->reconnect=!(flags&RTE_VHOST_USER_NO_RECONNECT);
if(vsocket->reconnect&&reconn_tid==0){
if(vhost_user_reconnect_init()!=0)
gotoout_mutex;
}
}else{
vsocket->is_server=true;
}
ret=create_unix_socket(vsocket);
if(ret gotoout_mutex;
}
vhost_user.vsockets[vhost_user.vsocket_cnt++]=vsocket;
pthread_mutex_unlock(&vhost_user.mutex);
returnret;
}

發(fā)送數(shù)據(jù)處理過程

vhost-user前端:在vhost-user接口創(chuàng)建之后,會(huì)調(diào)用rte_vhost_driver_start函數(shù):首先根據(jù)UNIX domainsocket的文件路徑path找到對(duì)應(yīng)的socket,然后會(huì)調(diào)用函數(shù)創(chuàng)建監(jiān)聽線程,

這個(gè)線程的處理函數(shù)是fdset_event_dispatch會(huì)去監(jiān)聽vhost_user.fdset指定的socket fd的讀寫操作,進(jìn)而實(shí)現(xiàn)和vhost-user后端的通信。這部分的實(shí)現(xiàn)代碼在:dpdk-stable-18.11.11/lib/librte_vhost/socket.c的第1094行。

intrte_vhost_driver_start(constchar*path)
{
structvhost_user_socket*vsocket;
staticpthread_tfdset_tid;
pthread_mutex_lock(&vhost_user.mutex);
vsocket=find_vhost_user_socket(path);
pthread_mutex_unlock(&vhost_user.mutex);
if(!vsocket)
return-1;
if(fdset_tid==0){
/**
*createapipewhichwillbewaitedbypollandnotifiedto
*rebuildthewaitlistofpoll.
*/
if(fdset_pipe_init(&vhost_user.fdset) RTE_LOG(ERR,VHOST_CONFIG,
"failedtocreatepipeforvhostfdset ");
return-1;
}
intret=rte_ctrl_thread_create(&fdset_tid,
"vhost-events",NULL,fdset_event_dispatch,
&vhost_user.fdset);
if(ret!=0){
RTE_LOG(ERR,VHOST_CONFIG,
"failedtocreatefdsethandlingthread");
fdset_pipe_uninit(&vhost_user.fdset);
return-1;
}
}
if(vsocket->is_server)
returnvhost_user_start_server(vsocket);
else
returnvhost_user_start_client(vsocket);
}

vhost-user后端:當(dāng)vhost-user前端(QEMU虛擬機(jī)的DPDK應(yīng)用程序)向UNIX domain socket寫入事件的時(shí)候,之前所說的那個(gè)監(jiān)聽線程會(huì)捕獲到這個(gè)事件,調(diào)用vhost_user_read_cb函數(shù)進(jìn)行處理,最終會(huì)調(diào)用vhost_user_msg_handler函數(shù),根據(jù)不同的消息類型做不同的處理。

這部分的實(shí)現(xiàn)代碼在:dpdk-stable-18.11.11/lib/librte_vhost/socket.c的第293行。

staticvoid
vhost_user_read_cb(intconnfd,void*dat,int*remove)
{
structvhost_user_connection*conn=dat;
structvhost_user_socket*vsocket=conn->vsocket;
intret;
ret=vhost_user_msg_handler(conn->vid,connfd);
if(ret structvirtio_net*dev=get_device(conn->vid);
close(connfd);
*remove=1;
if(dev)
vhost_destroy_device_notify(dev);
if(vsocket->notify_ops->destroy_connection)
vsocket->notify_ops->destroy_connection(conn->vid);
vhost_destroy_device(conn->vid);
if(vsocket->reconnect){
create_unix_socket(vsocket);
vhost_user_start_client(vsocket);
}
pthread_mutex_lock(&vsocket->conn_mutex);
TAILQ_REMOVE(&vsocket->conn_list,conn,next);
pthread_mutex_unlock(&vsocket->conn_mutex);
free(conn);
}
}

收發(fā)數(shù)據(jù)包的函數(shù)分別是eth_vhost_rx和eth_vhost_tx。代碼的具體實(shí)現(xiàn)在dpdk-stable-18.11.11/drivers/net/vhost/rte_eth_vhost.c中。

函數(shù)eth_dev_vhost_create用來創(chuàng)建vhost-user的后端設(shè)備的時(shí)候,會(huì)注冊(cè)發(fā)送和接收數(shù)據(jù)的回調(diào)函數(shù)為eth_vhost_rx和eth_vhost_tx。

在DPDK中,發(fā)送和接收數(shù)據(jù)包的代碼都是在DPDK中實(shí)現(xiàn)的,代碼的可讀性比較好。只是特別要注意的是同樣的DPDK代碼,運(yùn)行的位置不一樣:前端是在QEMU虛擬機(jī)中運(yùn)行的DPDK應(yīng)用程序,后端運(yùn)行在OVS-DPDK中。

staticint
eth_dev_vhost_create(structrte_vdev_device*dev,char*iface_name,
int16_tqueues,constunsignedintnuma_node,uint64_tflags)
{
constchar*name=rte_vdev_device_name(dev);
structrte_eth_dev_data*data;
structpmd_internal*internal=NULL;
structrte_eth_dev*eth_dev=NULL;
structether_addr*eth_addr=NULL;
structrte_vhost_vring_state*vring_state=NULL;
structinternal_list*list=NULL;
VHOST_LOG(INFO,"CreatingVHOST-USERbackendonnumasocket%u ",
numa_node);
list=rte_zmalloc_socket(name,sizeof(*list),0,numa_node);
if(list==NULL)
gotoerror;
/*reserveanethdeventry*/
eth_dev=rte_eth_vdev_allocate(dev,sizeof(*internal));
if(eth_dev==NULL)
gotoerror;
data=eth_dev->data;
eth_addr=rte_zmalloc_socket(name,sizeof(*eth_addr),0,numa_node);
if(eth_addr==NULL)
gotoerror;
data->mac_addrs=eth_addr;
*eth_addr=base_eth_addr;
eth_addr->addr_bytes[5]=eth_dev->data->port_id;
vring_state=rte_zmalloc_socket(name,
sizeof(*vring_state),0,numa_node);
if(vring_state==NULL)
gotoerror;
/*nowputitalltogether
*-storequeuedataininternal,
*-pointeth_dev_datatointernals
*-andpointeth_devstructuretoneweth_dev_datastructure
*/
internal=eth_dev->data->dev_private;
internal->dev_name=strdup(name);
if(internal->dev_name==NULL)
gotoerror;
internal->iface_name=rte_malloc_socket(name,strlen(iface_name)+1,
0,numa_node);
if(internal->iface_name==NULL)
gotoerror;
strcpy(internal->iface_name,iface_name);
list->eth_dev=eth_dev;
pthread_mutex_lock(&internal_list_lock);
TAILQ_INSERT_TAIL(&internal_list,list,next);
pthread_mutex_unlock(&internal_list_lock);
rte_spinlock_init(&vring_state->lock);
vring_states[eth_dev->data->port_id]=vring_state;
data->nb_rx_queues=queues;
data->nb_tx_queues=queues;
internal->max_queues=queues;
internal->vid=-1;
data->dev_link=pmd_link;
data->dev_flags=RTE_ETH_DEV_INTR_LSC;
eth_dev->dev_ops=&ops;
/*finallyassignrxandtxops*/
eth_dev->rx_pkt_burst=eth_vhost_rx;
eth_dev->tx_pkt_burst=eth_vhost_tx;
if(rte_vhost_driver_register(iface_name,flags))
gotoerror;
if(rte_vhost_driver_callback_register(iface_name,&vhost_ops) VHOST_LOG(ERR,"Can'tregistercallbacks ");
gotoerror;
}
if(rte_vhost_driver_start(iface_name) VHOST_LOG(ERR,"Failedtostartdriverfor%s ",
iface_name);
gotoerror;
}
rte_eth_dev_probing_finish(eth_dev);
return0;
error:
if(internal){
rte_free(internal->iface_name);
free(internal->dev_name);
}
rte_free(vring_state);
rte_eth_dev_release_port(eth_dev);
rte_free(list);
return-1;
}

02

vDPA

DPDK場(chǎng)景下的vhost-user是virtio-net在用戶態(tài)的實(shí)現(xiàn)。和內(nèi)核的實(shí)現(xiàn)相比,提高了網(wǎng)絡(luò)數(shù)據(jù)的處理能力。但畢竟還是純軟件層面的實(shí)現(xiàn),在性能上肯定比不過硬件層面的實(shí)現(xiàn)。

為了進(jìn)一步提升性能,Intel還推出了vDPA (vHost Data Path Acceleration) 的硬件解決方案,直接讓網(wǎng)卡與虛擬機(jī)內(nèi)的virtio虛擬隊(duì)列交互,把數(shù)據(jù)包DMA到虛擬機(jī)的緩存內(nèi),在支持了virtio標(biāo)準(zhǔn)的基礎(chǔ)上實(shí)現(xiàn)了真正意義上的零拷貝。

在DPDK 18.05之后的版本中,已經(jīng)開始支持vDPA的特性了。vDPA這部分的實(shí)現(xiàn)主要是在網(wǎng)卡中,相當(dāng)于把virtio后端實(shí)現(xiàn)在網(wǎng)卡中了。

所以,我們這里只關(guān)注一下virtio前端和vDPA設(shè)備之間的關(guān)聯(lián)。這部分實(shí)現(xiàn)的相關(guān)代碼在dpdk-stable-18.11.11/examples/vdpa/main.c,第143行start_vdpa函數(shù)中的rte_vhost_driver_attach_vdpa_device函數(shù)中實(shí)現(xiàn)了vhost-user的vsocket數(shù)據(jù)結(jié)構(gòu)和vDPA設(shè)備ID的關(guān)聯(lián)。

staticint
start_vdpa(structvdpa_port*vport)
{
intret;
char*socket_path=vport->ifname;
intdid=vport->did;
if(client_mode)
vport->flags|=RTE_VHOST_USER_CLIENT;
if(access(socket_path,F_OK)!=-1&&!client_mode){
RTE_LOG(ERR,VDPA,
"%sexists,pleaseremoveitorspecifyanotherfileandtryagain. ",
socket_path);
return-1;
}
ret=rte_vhost_driver_register(socket_path,vport->flags);
if(ret!=0)
rte_exit(EXIT_FAILURE,
"registerdriverfailed:%s ",
socket_path);
ret=rte_vhost_driver_callback_register(socket_path,
&vdpa_sample_devops);
if(ret!=0)
rte_exit(EXIT_FAILURE,
"registerdriveropsfailed:%s ",
socket_path);
ret=rte_vhost_driver_attach_vdpa_device(socket_path,did);
if(ret!=0)
rte_exit(EXIT_FAILURE,
"attachvdpadevicefailed:%s ",
socket_path);
if(rte_vhost_driver_start(socket_path) rte_exit(EXIT_FAILURE,
"startvhostdriverfailed:%s ",
socket_path);
return0;
}
int
rte_vhost_driver_attach_vdpa_device(constchar*path,intdid)
{
structvhost_user_socket*vsocket;
if(rte_vdpa_get_device(did)==NULL||path==NULL)
return-1;
pthread_mutex_lock(&vhost_user.mutex);
vsocket=find_vhost_user_socket(path);
if(vsocket)
vsocket->vdpa_dev_id=did;
pthread_mutex_unlock(&vhost_user.mutex);
returnvsocket?0:-1;
}

原文標(biāo)題:virtio技術(shù)的演進(jìn)和發(fā)展 (2/2)

文章出處:【微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11465

    瀏覽量

    212813
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    13

    文章

    9698

    瀏覽量

    87306
  • 虛擬機(jī)
    +關(guān)注

    關(guān)注

    1

    文章

    962

    瀏覽量

    29064

原文標(biāo)題:virtio技術(shù)的演進(jìn)和發(fā)展 (2/2)

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    完整版—單片機(jī)編程思想(推薦下載!)

    出數(shù)據(jù)驅(qū)動(dòng)、并行多任務(wù)、面向?qū)ο蟮戎匾幊?b class='flag-5'>思想。這些思想既可獨(dú)立運(yùn)用,又可有機(jī)結(jié)合成一個(gè)體系,是我們實(shí)踐中解決問題的致勝法寶。本書以實(shí)例為基礎(chǔ),分6章對(duì)這一思想體系進(jìn)行了闡述。闡述通常以提出
    發(fā)表于 04-16 15:06

    AI正在對(duì)硬件互連提出“過分”要求 | Samtec于Keysight開放日深度分享

    ?在Keysight實(shí)驗(yàn)室開放日上海站做深度分享時(shí),提出了以上這樣的問題。 本次活動(dòng)由Keysight主辦,在上海、北京舉辦開放實(shí)驗(yàn)室主題日活動(dòng),攜手Samtec的技術(shù)專家,共同探討確保 AI 互連穩(wěn)健性的趨勢(shì)、挑戰(zhàn)和解決方案。 從摩爾定律看AI發(fā)展 回顧半導(dǎo)體行業(yè),英特爾創(chuàng)始人戈登?摩爾
    發(fā)表于 02-26 11:09 ?232次閱讀
    AI正在對(duì)硬件互連<b class='flag-5'>提出</b>“過分”要求 | Samtec于Keysight開放日深度分享

    北大攜智元機(jī)器?團(tuán)隊(duì)提出OmniManip架構(gòu)

    近日,北京大學(xué)與智元機(jī)器人的聯(lián)合實(shí)驗(yàn)室有了重大成果,北?攜?智元機(jī)器?團(tuán)隊(duì)提出 OmniManip 架構(gòu)。 在具身智能領(lǐng)域,將視覺語言基礎(chǔ)模型(VLMs)應(yīng)用于機(jī)器人實(shí)現(xiàn)通用操作一直是核心問題。目前
    的頭像 發(fā)表于 01-24 09:57 ?446次閱讀

    大連理工提出基于Wasserstein距離(WD)的知識(shí)蒸餾方法

    的機(jī)制,應(yīng)用于中間層蒸餾時(shí)存在問題,其無法處理不重疊的分布且無法感知底層流形的幾何結(jié)構(gòu)。 為了解決這些問題,大連理工大學(xué)的研究人員提出了一種基于 Wasserstein 距離(WD)的知識(shí)蒸餾方法。所提出方法在圖像分類和目標(biāo)檢測(cè)任務(wù)上均取得了當(dāng)前最好的性能,論文已被 Ne
    的頭像 發(fā)表于 01-21 09:45 ?561次閱讀

    神經(jīng)網(wǎng)絡(luò)理論研究的物理學(xué)思想介紹

    本文主要介紹神經(jīng)網(wǎng)絡(luò)理論研究的物理學(xué)思想 神經(jīng)網(wǎng)絡(luò)在當(dāng)今人工智能研究和應(yīng)用中發(fā)揮著不可替代的作用。它是人類在理解自我(大腦)的過程中產(chǎn)生的副產(chǎn)品,以此副產(chǎn)品,人類希望建造一個(gè)機(jī)器智能來實(shí)現(xiàn)機(jī)器文明
    的頭像 發(fā)表于 01-16 11:16 ?808次閱讀
    神經(jīng)網(wǎng)絡(luò)理論研究的物理學(xué)<b class='flag-5'>思想</b>介紹

    中國電提出大模型推理加速新范式Falcon

    Enhanced Semi-Autoregressive Drafting and Custom-Designed Decoding Tree》已被 AAAI 2025 接收。 論文中提出
    的頭像 發(fā)表于 01-15 13:49 ?712次閱讀
    中國電<b class='flag-5'>提出</b>大模型推理加速新范式Falcon

    Vue3設(shè)計(jì)思想及響應(yīng)式源碼剖析

    DOM進(jìn)行了重寫、對(duì)模板的編譯進(jìn)行了優(yōu)化操作... 2、Vue3設(shè)計(jì)思想 ?Vue3.0更注重模塊上的拆分,在2.0中無法單獨(dú)使用部分模塊。需要引入
    的頭像 發(fā)表于 12-20 10:24 ?394次閱讀

    融合計(jì)算是如何提出來的

    融合計(jì)算是微觀和宏觀視角算力提升策略的總結(jié),是三個(gè)維度融合(異構(gòu)融合x軟硬件融合x云邊端融合)的統(tǒng)稱,那么融合計(jì)算是如何提出來的?為什么融合計(jì)算有且僅有三個(gè)維度的融合? ? 性能和算力 1.1 性能
    的頭像 發(fā)表于 12-10 09:51 ?439次閱讀
    融合計(jì)算是如何<b class='flag-5'>提出</b>來的

    LED的種類以及其特點(diǎn)

    LED在我們生活中的應(yīng)用非常廣泛,除了可以用作照明、開關(guān)、傳感器和背光源之外,還可以用于戶外顯示屏和路燈、以及汽車、醫(yī)療和農(nóng)業(yè)等的特殊用途中。用戶可以根據(jù)應(yīng)用需求,使用不同形狀和波長(zhǎng)的LED。本文將為您介紹LED的種類以及每種LED的特點(diǎn)。
    的頭像 發(fā)表于 10-17 10:13 ?1851次閱讀
    LED的種類<b class='flag-5'>以及</b>其特點(diǎn)

    使用stm32f767將tlv320adc3140配置為tdm工作模式,如何將每個(gè)通道數(shù)據(jù)單獨(dú)提出出來進(jìn)而播放呢?

    使用stm32f767將tlv320adc3140配置為tdm工作模式,采集到了四通道差分輸入的音頻數(shù)據(jù),如何將每個(gè)通道數(shù)據(jù)單獨(dú)提出出來進(jìn)而播放呢?
    發(fā)表于 10-09 07:47

    當(dāng)前主流的大模型對(duì)于底層推理芯片提出了哪些挑戰(zhàn)

    隨著大模型時(shí)代的到來,AI算力逐漸變成重要的戰(zhàn)略資源,對(duì)現(xiàn)有AI芯片也提出了前所未有的挑戰(zhàn):大算力的需求、高吞吐量與低延時(shí)、高效內(nèi)存管理、能耗等等。
    的頭像 發(fā)表于 09-24 16:57 ?1069次閱讀

    示波器使用以及信號(hào)處理

    有沒有大神可以教我示波器的使用以及信號(hào)的處理,可有償。
    發(fā)表于 07-27 11:45

    Transformer架構(gòu)在自然語言處理中的應(yīng)用

    隨著人工智能技術(shù)的飛速發(fā)展,自然語言處理(NLP)領(lǐng)域取得了顯著的進(jìn)步。其中,Transformer架構(gòu)的提出,為NLP領(lǐng)域帶來了革命性的變革。本文將深入探討Transformer架構(gòu)的核心思想、組成部分以及在自然語言處理領(lǐng)域的
    的頭像 發(fā)表于 07-09 11:42 ?1495次閱讀

    歐盟對(duì)蘋果數(shù)字市場(chǎng)合規(guī)性提出嚴(yán)重質(zhì)疑

    在科技巨頭與監(jiān)管機(jī)構(gòu)的博弈中,蘋果公司近日再次成為焦點(diǎn)。6月19日,歐盟競(jìng)爭(zhēng)事務(wù)專員瑪格麗特?維斯塔格在接受CNBC采訪時(shí),對(duì)蘋果公司在《歐洲數(shù)字市場(chǎng)法案》(DMA)合規(guī)性方面提出了尖銳的批評(píng),指出蘋果面臨“許多非常嚴(yán)重”的問題。
    的頭像 發(fā)表于 06-20 09:30 ?583次閱讀

    動(dòng)態(tài)線程池思想學(xué)習(xí)及實(shí)踐

    相關(guān)文檔 美團(tuán)線程池實(shí)踐:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html 線程池思想解析:https
    的頭像 發(fā)表于 06-13 15:43 ?1481次閱讀
    動(dòng)態(tài)線程池<b class='flag-5'>思想</b>學(xué)習(xí)及實(shí)踐