数据帧收发主要函数及netdevice 结构.docx
- 文档编号:5767732
- 上传时间:2023-01-01
- 格式:DOCX
- 页数:21
- 大小:216.15KB
数据帧收发主要函数及netdevice 结构.docx
《数据帧收发主要函数及netdevice 结构.docx》由会员分享,可在线阅读,更多相关《数据帧收发主要函数及netdevice 结构.docx(21页珍藏版)》请在冰豆网上搜索。
数据帧收发主要函数及netdevice结构
**
* netif_rx - postbuffertothenetworkcode
* @skb:
buffertopost
*
* Thisfunctionreceivesapacketfromadevicedriverandqueuesitfor
* theupper(protocol)levelstoprocess. Italwayssucceeds.Thebuffer
* maybedroppedduringprocessingforcongestioncontrolorbythe
* protocollayers.
*
* returnvalues:
* NET_RX_SUCCESS (nocongestion)
* NET_RX_DROP (packetwasdropped)
*
*/
int netif_rx( struct sk_buff * skb)
{
struct softnet_data * queue;
unsigned long flags ;
/*ifnetpollwantsit,pretendweneversawit*/
if (netpoll_rx (skb ))
return NET_RX_DROP;
if (!
skb->tstamp .tv64 )//得到帧接收的时间
net_timestamp(skb);
/*
*Thecodeisrearrangedsothatthepathisthemost
*shortwhenCPUiscongested,butisstilloperating.
*/
local_irq_save(flags);
queue = &__get_cpu_var (softnet_data );//获取当前CPU的softnet_data数据
__get_cpu_var(netdev_rx_stat ).total ++;//当前CPU接收的帧数+1
if (queue->input_pkt_queue .qlen <= netdev_max_backlog){
//监测设备是否还有空间来存储帧,如果空间已满,表示网络阻塞严重,则返回一个错误,此后cpu将丢掉再来的帧。
if (queue->input_pkt_queue .qlen ){
enqueue:
//将该帧加入到softnet_data队列
__skb_queue_tail(&queue ->input_pkt_queue, skb);
local_irq_restore(flags);
return NET_RX_SUCCESS;
}
//当队列是空的时候,表明这个队列并没有被软中断所schedule,因此我们需要将此队列加入到软中断的处理链表中。
可以看到加入的正好是backlog,由于调用netif_rx的是非napi的驱动,因此backlog就是初始化时的process_backlog函数。
napi_schedule(&queue ->backlog);
goto enqueue;
}
__get_cpu_var(netdev_rx_stat ).dropped ++;
local_irq_restore(flags);
kfree_skb(skb);
return NET_RX_DROP;
}
//上面代码中用到一个关键的数据结构softnet_data,在网卡收发数据的时候,需要维护一个缓冲区队列,来缓存可能存在的突发数据,在协议栈中用一个队列层来表示该缓冲区,队列层位于数据链路层和网络层之间。
softnet_data就是数据链路层中的数据结构,它是一个Per-CPU变量,每个CPU都有一个
/**
* netif_receive_skb-processreceivebufferfromnetwork
* @skb:
buffertoprocess
*
* netif_receive_skb()isthemainreceivedataprocessingfunction.
* Italwayssucceeds.Thebuffermaybedroppedduringprocessing
* forcongestioncontrolorbytheprotocollayers.
*
* Thisfunctionmayonlybecalledfromsoftirqcontextandinterrupts
* shouldbeenabled.
*
* Returnvalues(usuallyignored):
* NET_RX_SUCCESS:
nocongestion
* NET_RX_DROP:
packetwasdropped
*/
//netif_receive_skb是对于netif_rx的NAPI对等函数;它递交一个报文给内核.当一个NAPI兼容的驱动已耗尽接收报文的供应,它应当重开中断,并且调用netif_rx_complete(现在是 __napi_complete())来停止轮询.
int netif_receive_skb( struct sk_buff * skb)
{
struct packet_type * ptype,*pt_prev ;
struct net_device * orig_dev;
struct net_device * master;
struct net_device * null_or_orig;
struct net_device * null_or_bond;
int ret = NET_RX_DROP;
__be16type;
if (!
skb->tstamp .tv64 )
net_timestamp(skb);
if (vlan_tx_tag_present (skb ) && vlan_hwaccel_do_receive(skb))
return NET_RX_SUCCESS;
/*ifwe'vegottenherethroughNAPI,checknetpoll*/
if (netpoll_receive_skb (skb ))
return NET_RX_DROP;
if (!
skb->skb_iif )
skb->skb_iif = skb ->dev-> ifindex;//记录帧的入口
null_or_orig = NULL;
orig_dev = skb->dev;
master = ACCESS_ONCE (orig_dev ->master);
if (master){
if (skb_bond_should_drop (skb , master ))
null_or_orig = orig_dev ; /*deliveronlyexactmatch*/
else
skb->dev = master ;
}
__get_cpu_var(netdev_rx_stat ).total ++;
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
skb->mac_len = skb ->network_header - skb->mac_header ;
pt_prev = NULL;
rcu_read_lock();
#ifdefCONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS){
skb->tc_verd = CLR_TC_NCLS( skb->tc_verd );
goto ncls;
}
#endif
//处理ptype_all上所有的packet_type->func(),这里先提一下Linux是根据packet_type通过 dev_add_pack()函数来注册相应的处理函数,后面会讲如何注册,每种包对应哪个处理函数
// staticstructlist_headptype_all__read_mostly;
list_for_each_entry_rcu(ptype, &ptype_all , list ){
if (ptype->dev == null_or_orig || ptype->dev == skb-> dev ||
ptype->dev == orig_dev){
if (pt_prev)
ret = deliver_skb (skb , pt_prev , orig_dev );//调用相应的包处理函数
pt_prev = ptype;
}
}
#ifdefCONFIG_NET_CLS_ACT
skb = handle_ing (skb , &pt_prev , &ret , orig_dev );
if (!
skb)
goto out;
ncls:
#endif
//若编译内核时选上BRIDGE,下面会执行网桥模块
skb = handle_bridge (skb , &pt_prev , &ret , orig_dev );
if (!
skb)
goto out;
//编译内核时选上MAC_VLAN模块,下面才会执行
skb = handle_macvlan (skb , &pt_prev , &ret , orig_dev );
if (!
skb)
goto out;
/*
*MakesureframesreceivedonVLANinterfacesstackedon
*bondinginterfacesstillmaketheirwaytoanybasebonding
*devicethatmayhaveregisteredforaspecificptype. The
*handlermayhavetoadjustskb->devandorig_dev.
*/
null_or_bond = NULL;
if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
(vlan_dev_real_dev( skb->dev)->priv_flags & IFF_BONDING)){
null_or_bond = vlan_dev_real_dev (skb ->dev);
}
//最后type=skb->protocol;&ptype_base[ntohs(type)&15]处理ptype_base[ntohs(type)&15]上的所有的packet_type->func(),根据第二层不同协议来进入不同的钩子函数,重要的有:
ip_rcv(),arp_rcv()
type = skb->protocol ;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs (type )& PTYPE_HASH_MASK], list){
if (ptype->type == type && (ptype ->dev == null_or_orig ||
ptype->dev == skb-> dev || ptype->dev == orig_dev ||
ptype->dev == null_or_bond)){
if (pt_prev)
ret = deliver_skb (skb , pt_prev , orig_dev );
pt_prev = ptype;
}
}
if (pt_prev){
ret = pt_prev ->func( skb, skb->dev, pt_prev , orig_dev );
} else {
kfree_skb(skb);
/*Jamal,nowyouwillnotabletoescapeexplaining
*mehowyouweregoingtousethis.:
-)
*/
ret = NET_RX_DROP ;
}
out:
rcu_read_unlock();
return ret;
}
/**
* dev_queue_xmit-transmitabuffer
* @skb:
buffertotransmit
*
* Queueabufferfortransmissiontoanetworkdevice.Thecallermust
* havesetthedeviceandpriorityandbuiltthebufferbeforecalling
* thisfunction.Thefunctioncanbecalledfromaninterrupt.
*
* Anegativeerrnocodeisreturnedonafailure.Asuccessdoesnot
* guaranteetheframewillbetransmittedasitmaybedroppeddue
* tocongestionortrafficshaping.
*
*-----------------------------------------------------------------------------------
* Inoticethismethodcanalsoreturnerrorsfromthequeuedisciplines,
* includingNET_XMIT_DROP,whichisapositivevalue. So,errorscanalso
* bepositive.
*
* Regardlessofthereturnvalue,theskbisconsumed,soitiscurrently
* difficulttoretryasendtothismethod. (Youcanbumptherefcount
* beforesendingtoholdareferenceforretryifyouarecareful.)
*
* Whencallingthismethod,interruptsMUSTbeenabled. Thisisbecause
* theBHenablecodemusthaveIRQsenabledsothatitwillnotdeadlock.
* --BLG
*/
int dev_queue_xmit( struct sk_buff * skb)
{
struct net_device * dev = skb->dev;
struct netdev_queue * txq;
struct Qdisc * q;
int rc =- ENOMEM;
/*GSOwillhandlethefollowingemulationsdirectly.*/
if (netif_needs_gso (dev , skb ))//如果是GSO数据包,且设备支持GSO数据包的处理
goto gso;
/*Convertapagedskbtolinear,ifrequired*/
if (skb_needs_linearize (skb , dev ) && __skb_linearize(skb))
goto out_kfree_skb;
/*Ifpacketisnotchecksummedanddevicedoesnotsupport
*checksummingforthisprotocol,completechecksumminghere.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL){
skb_set_transport_header(skb, skb->csum_start -
skb_headroom(skb));
if (!
dev_can_checksum (dev , skb ) && skb_checksum_help(skb))
goto out_kfree_skb;
}
gso:
/*Disablesoftirqsforvariouslocksbelow.Also
*stopspreemptionforRCU.
*/
rcu_read_lock_bh();
txq = dev_pick_tx (dev , skb );
q = rcu_dereference_bh(txq->qdisc );
#ifdefCONFIG_NET_CLS_ACT
skb->tc_verd = SET_TC_AT( skb->tc_verd , AT_EGRESS );
#endif
if (q->enqueue ){
rc = __dev_xmit_skb (skb , q , dev , txq );
goto out;
}
/*Thedevicehasnoqueue.Commoncaseforsoftwaredevices:
loopback,allthesortsoftunnels...
Really,itisunlikelythatnetif_tx_lockprotectionisnecessary
here. (f.e.loopbackandIPtunnelsarecleanignoringstatistics
counters.)
However,itispossible,thattheyrelyonprotection
madebyushere.
Checkthisandshotthelock.Itisnotpronefromdeadlocks.
Eithershotnoqueueqdisc,itisevensimpler8)
*/
if (dev->flag
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据帧收发主要函数及netdevice 结构 数据 收发 主要 函数 netdevice