高性能网络IO框架netmap源码分析Word文档下载推荐.docx
- 文档编号:19817518
- 上传时间:2023-01-10
- 格式:DOCX
- 页数:38
- 大小:37.04KB
高性能网络IO框架netmap源码分析Word文档下载推荐.docx
《高性能网络IO框架netmap源码分析Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《高性能网络IO框架netmap源码分析Word文档下载推荐.docx(38页珍藏版)》请在冰豆网上搜索。
e1000_probe里面很多代码看不明白,但是不影响我们对netmap的分析。
通过netmap的patch,知道是在e1000完成一系列硬件初始化以后,并注册成功,这时调用e1000_netmap_attach
@@-1175,6+1183,10@@staticint__devinite1000_probe(struct
if(err)
gotoerr_register;
+#ifdefDEV_NETMAP
+e1000_netmap_attach(adapter);
+#endif/*DEV_NETMAP*/
+
/*printbustype/speed/widthinfo*/
e_info(probe,"
(PCI%s:
%dMHz:
%d-bit)%pM\n"
((hw->
bus_type==e1000_bus_type_pcix)?
"
-X"
:
"
),
下面是e1000_netmap_attach的代码
staticvoid
e1000_netmap_attach(structSOFTC_T*adapter)
{
structnetmap_adapterna;
bzero(&
na,sizeof(na));
na.ifp=adapter->
netdev;
na.separate_locks=0;
na.num_tx_desc=adapter->
tx_ring[0].count;
na.num_rx_desc=adapter->
rx_ring[0].count;
na.nm_register=e1000_netmap_reg;
na.nm_txsync=e1000_netmap_txsync;
na.nm_rxsync=e1000_netmap_rxsync;
netmap_attach(&
na,1);
}
SOFTC_T是一个宏定义,对于e1000,实际上是e1000_adapter,即e1000网卡驱动对应的privatedata。
下面是structnetmap_adapter的定义
/*
*Thisstructextendsthe'
structadapter'
(or
*equivalent)devicedescriptor.Itcontainsallfieldsneededto
*supportnetmapoperation.
*/
structnetmap_adapter{
/*
*Onlinuxwedonothaveagoodwaytotellifaninterface
*isnetmap-capable.Soweusethefollowingtrick:
*NA(ifp)pointshere,andthefirstentry(whichhopefully
*alwaysexistsandisatleast32bits)containsamagic
*valuewhichwecanusetodetectthattheinterfaceisgood.
*/
uint32_tmagic;
uint32_tna_flags;
/*futureplaceforIFCAP_NETMAP*/
intrefcount;
/*numberofuser-spacedescriptorsusingthis
interface,whichisequaltothenumberof
structnetmap_ifobjsinthemappedregion.*/
*Theselwakeupintheinterruptthreadcanuseper-ring
*and/orglobalwaitqueues.Wetrackhowmanyclients
*ofeachtypewehavesowecanoptimizethedrivers,
*andespeciallyavoidhugecontentiononthelocks.
intna_single;
/*threadsattachedtoasinglehwqueue*/
intna_multi;
/*threadsattachedtomultiplehwqueues*/
intseparate_locks;
/*setiftheinterfacesuportsdifferent
locksforrx,txandcore.*/
u_intnum_rx_rings;
/*numberofadapterreceiverings*/
u_intnum_tx_rings;
/*numberofadaptertransmitrings*/
u_intnum_tx_desc;
/*numberofdescriptorineachqueue*/
u_intnum_rx_desc;
/*tx_ringsandrx_ringsareprivatebutallocated
*asacontiguouschunkofmemory.Eacharrayhas
*N+1entries,fortheadapterqueuesandforthehostqueue.
structnetmap_kring*tx_rings;
/*arrayofTXrings.*/
structnetmap_kring*rx_rings;
/*arrayofRXrings.*/
NM_SELINFO_Ttx_si,rx_si;
/*globalwaitqueues*/
/*copyofif_qflushandif_transmitpointers,tointercept
*packetsfromthenetworkstackwhennetmapisactive.
int(*if_transmit)(structifnet*,structmbuf*);
/*referencestotheifnetanddeviceroutines,usedby
*thegenericnetmapfunctions.
structifnet*ifp;
/*adapterisifp->
if_softc*/
NM_LOCK_Tcore_lock;
/*usedifnodevicelockavailable*/
int(*nm_register)(structifnet*,intonoff);
void(*nm_lock)(structifnet*,intwhat,u_intringid);
int(*nm_txsync)(structifnet*,u_intring,intlock);
int(*nm_rxsync)(structifnet*,u_intring,intlock);
intbdg_port;
#ifdeflinux
structnet_device_opsnm_ndo;
intif_refcount;
//XXXadditionsforbridge
#endif/*linux*/
};
从structnetmap_adapter可以看出,netmap的注释是相当详细。
所以后面,我不再列出netmap的结构体定义,大家可以自己查看,免得满篇全是代码。
————这样的注释,有几个公司能够做到?
e1000_netmap_attach完成简单的初始化工作以后,调用netmap_attach执行真正的attach工作。
前者是完成与具体驱动相关的attach工作或者说是准备工作,而后者则是真正的attach。
int
netmap_attach(structnetmap_adapter*na,intnum_queues)
intn,size;
void*buf;
/*这里ifnet又是一个宏,linux下ifnet实际上是net_device*/
structifnet*ifp=na->
ifp;
if(ifp==NULL){
D("
ifpnotset,givingup"
);
returnEINVAL;
}
/*clearotherfields?
na->
refcount=0;
/*初始化接收和发送ring*/
if(na->
num_tx_rings==0)
num_tx_rings=num_queues;
num_rx_rings=num_queues;
/*oneachdirectionwehaveN+1resources
*0..n-1arethehardwarerings
*nistheringattachedtothestack.
/*
这么详细的注释。
还用得着我说吗?
0到n-1的ring是用于转发的ring,而n是本机协议栈的队列
n+1为哨兵位置
n=na->
num_rx_rings+na->
num_tx_rings+2;
/*netmap_adapter与其ring统一申请内存*/
size=sizeof(*na)+n*sizeof(structnetmap_kring);
这里的malloc,实际上为kmalloc。
这里还有一个小trick。
M_DEVBUF,M_NOWAIT和M_ZERO都是FreeBSD的定义。
那么在linux下怎么使用呢?
我开始以为其被定义为linux对应的flag,如GFP_ATOMIC和__GFP_ZERO,于是grep了M_NOWAIT,也没有找到任何的宏定义。
正在奇怪的时候,想到一种情况。
让我们看看malloc的宏定义
/*usevolatiletofixaprobablecompilererroron2.6.25*/
#definemalloc(_size,type,flags)\
({volatileint_v=_size;
kmalloc(_v,GFP_ATOMIC|__GFP_ZERO);
})
这里type和flags完全没有任何引用的地方。
所以在linux下,上面的M_DEVBUG实际上直接被忽略掉了。
buf=malloc(size,M_DEVBUF,M_NOWAIT|M_ZERO);
if(buf){
/*Linux下重用了structnet_device->
ax25_ptr,用其保存buf的地址*/
WNA(ifp)=buf;
/*初始化tx_rings和rx_rings,tx_rings和rx_rings之间用了一个额外的ring分隔,目前不知道这个ring是哨兵呢,还是本主机的ring*/
tx_rings=(void*)((char*)buf+sizeof(*na));
rx_rings=na->
tx_rings+na->
num_tx_rings+1;
/*复制netmap_device并设置对应的标志位,用于表示其为netmap_device*/
bcopy(na,buf,sizeof(*na));
NETMAP_SET_CAPABLE(ifp);
na=buf;
/*Corelockinitializedhere.Othersareinitializedafter
*netmap_if_new.
mtx_init(&
na->
core_lock,"
netmapcorelock"
MTX_NETWORK_LOCK,
MTX_DEF);
nm_lock==NULL){
ND("
usingdefaultlocksfor%s"
ifp->
if_xname);
nm_lock=netmap_lock_wrapper;
/*这几行Linux才用的上的代码,是为linux网卡的驱动框架准备的。
未来有用处*/
if(ifp->
netdev_ops){
netdev_ops%p"
netdev_ops);
/*prepareacloneofthenetdevops*/
nm_ndo=*ifp->
netdev_ops;
nm_ndo.ndo_start_xmit=linux_netmap_start;
#endif
%sfor%s"
buf?
ok"
failed"
return(buf?
0:
ENOMEM);
完成了netmap_attach,e1000的probe函数e1000_probe即执行完毕。
前面e1000_probe的分析,按照Linux驱动框架,接下来就该e1000_open。
netmap并没有对e1000_open进行任何修改,而是改动了e1000_configure,其会被e1000_open及e1000_up调用。
e1000_configure的修改
按照惯例,还是先看diff文件
@@-393,6+397,10@@staticvoide1000_configure(structe1000
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+if(e1000_netmap_init_buffers(adapter))
+return;
/*callE1000_DESC_UNUSEDwhichalwaysleaves
*atleast1descriptorunusedtomakesure
*next_to_use!
=next_to_clean*/
从diff文件可以看出,netmap替代了原有的e1000申请ringbuffer的代码。
如果e1000_netmap_init_buffers成功返回,e1000_configure就直接退出了。
接下来进入e1000_netmap_init_buffers:
*Makethetxandrxringspointtothenetmapbuffers.
staticinte1000_netmap_init_buffers(structSOFTC_T*adapter)
structe1000_hw*hw=&
adapter->
hw;
structifnet*ifp=adapter->
structnetmap_adapter*na=NA(ifp);
structnetmap_slot*slot;
structe1000_tx_ring*txr=&
tx_ring[0];
unsignedinti,r,si;
uint64_tpaddr;
还记得前面的netmap_attach吗?
所谓的attach,即申请了netmap_adapter,并将net_device->
ax25_ptr保存了指针,并设置了NETMAP_SET_CAPABLE。
因此这里做一个sanitycheck,以免影响正常的网卡驱动
if(!
na||!
(na->
ifp->
if_capenable&
IFCAP_NETMAP))
return0;
/*e1000_no_rx_alloc如其名,为一个不该调用的函数,只输出一行错误日志*/
adapter->
alloc_rx_buf=e1000_no_rx_alloc;
for(r=0;
r<
num_rx_rings;
r++){
structe1000_rx_ring*rxr;
/*初始化对应的netmap对应的ring*/
slot=netmap_reset(na,NR_RX,r,0);
slot){
strange,nullnetmapring%d"
r);
/*得到e1000对应的ring*/
rxr=&
rx_ring[r];
for(i=0;
i<
rxr->
count;
i++){
//XXXtheskbcheckandcleanupcangoaway
structe1000_buffer*bi=&
rxr->
buffer_info[i];
/*将当前的buff索引转换为netmap的buff索引*/
si=netmap_idx_n2k(&
rx_rings[r],i);
/*获得netmap的buff的物理地址*/
PNMB(slot+si,&
paddr);
if(bi->
skb)
rxbuf%dwasset"
i);
bi->
skb=NULL;
//netmap_load_map(...)
/*现在网卡的这个buffer已经指向了netmap申请的buff地址了*/
E1000_RX_DESC(*rxr,i)->
buffer_addr=htole64(paddr);
next_to_use=0;
下面这几行代码没看明白怎么回事。
有明白的同学指点一下,多谢。
/*preservebuffersalreadymadeavailabletoclients*/
i=rxr->
count-1-na->
rx_rings[0].nr_hwavail;
if(i<
0)
i+=rxr->
inowis%d"
wmb();
/*Forcememorywritestocomplete*/
writel(i,hw->
hw_addr+rxr->
rdt);
初始化发送ring,与接收类似.
区别在于没有考虑发送多队列。
难道是因为e1000只可能是接收多队列,发送只可能是一个队列?
这个问题不影响后面的代码阅读。
咱们可以暂时将其假设为e1000只有一个发送队列
/*nowinitializethetxring(s)*/
slot=netmap_reset(na,NR_TX,0,0);
num_tx_desc;
tx_rings[0],i);
E1000_TX_DESC(*txr,i)->
return1;
e1000cleanrx_irq的修改
@@-3952,6+3973,11@@staticboole1000_clean_rx_irq(structe1
boolcleaned=false;
unsignedinttotal_rx_bytes=0,total_rx_packets=0;
+ND("
callingnetmap_rx_irq"
+if(netmap_rx_irq(netdev,0,work_done))
+return1;
/*seemstobeignored*/
+#endif/*DEV_NETMA
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 性能 网络 IO 框架 netmap 源码 分析