数据帧收发主要函数及netdevice 结构.docx

上传人:b****5 文档编号:5767732 上传时间:2023-01-01 格式:DOCX 页数:21 大小:216.15KB
下载 相关 举报
数据帧收发主要函数及netdevice 结构.docx_第1页
第1页 / 共21页
数据帧收发主要函数及netdevice 结构.docx_第2页
第2页 / 共21页
数据帧收发主要函数及netdevice 结构.docx_第3页
第3页 / 共21页
数据帧收发主要函数及netdevice 结构.docx_第4页
第4页 / 共21页
数据帧收发主要函数及netdevice 结构.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

数据帧收发主要函数及netdevice 结构.docx

《数据帧收发主要函数及netdevice 结构.docx》由会员分享,可在线阅读,更多相关《数据帧收发主要函数及netdevice 结构.docx(21页珍藏版)》请在冰豆网上搜索。

数据帧收发主要函数及netdevice 结构.docx

数据帧收发主要函数及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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1