转载地址http://blog.csdn.net/yming0221/article/details/7492423

作者:闫明

本文分析基于Linux Kernel 1.2.13

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

 上篇:

上一篇博文中我们从宏观上分析了Linux内核中网络栈的初始化过程,这里我们再从宏观上分析一下一个数据包在各网络层的传递的过程。

我们知道网络的OSI模型和TCP/IP模型层次结构如下:

上文中我们看到了网络栈的层次结构:

我们就从最底层开始追溯一个数据包的传递流程。

1、网络接口层

* 硬件监听物理介质,进行数据的接收,当接收的数据填满了缓冲区,硬件就会产生中断,中断产生后,系统会转向中断服务子程序。

* 在中断服务子程序中,数据会从硬件的缓冲区复制到内核的空间缓冲区,并包装成一个数据结构(sk_buff),然后调用对驱动层的接口函数netif_rx()将数据包发送给链路层。该函数的实现在net/inet/dev.c中,(在整个网络栈实现中dev.c文件的作用重大,它衔接了其下的驱动层和其上的网络层,可以称它为链路层模块的实现)

该函数的实现如下:

 

[cpp] view plaincopy
 
  1. /* 
  2.  *  Receive a packet from a device driver and queue it for the upper 
  3.  *  (protocol) levels.  It always succeeds. This is the recommended  
  4.  *  interface to use. 
  5.  *    从设备驱动层接受到的数据发送到协议的 
  6.  *    上层,该函数实际是一个接口。 
  7.  */  
  8.   
  9. void netif_rx(struct sk_buff *skb)  
  10. {  
  11.     static int dropping = 0;  
  12.   
  13.     /* 
  14.      *  Any received buffers are un-owned and should be discarded 
  15.      *  when freed. These will be updated later as the frames get 
  16.      *  owners. 
  17.      */  
  18.     skb->sk = NULL;  
  19.     skb->free = 1;  
  20.     if(skb->stamp.tv_sec==0)  
  21.         skb->stamp = xtime;  
  22.   
  23.     /* 
  24.      *  Check that we aren't overdoing things. 
  25.      */  
  26.   
  27.     if (!backlog_size)  
  28.         dropping = 0;  
  29.     else if (backlog_size > 300)  
  30.         dropping = 1;  
  31.   
  32.     if (dropping)   
  33.     {  
  34.         kfree_skb(skb, FREE_READ);  
  35.         return;  
  36.     }  
  37.   
  38.     /* 
  39.      *  Add it to the "backlog" queue.  
  40.      */  
  41. #ifdef CONFIG_SKB_CHECK  
  42.     IS_SKB(skb);  
  43. #endif    
  44.     skb_queue_tail(&backlog,skb);//加入队列backlog  
  45.     backlog_size++;  
  46.     
  47.     /* 
  48.      *  If any packet arrived, mark it for processing after the 
  49.      *  hardware interrupt returns. 
  50.      */  
  51.   
  52.     mark_bh(NET_BH);//下半部分bottom half技术可以减少中断处理程序的执行时间  
  53.     return;  
  54. }  


该函数中用到了bootom half技术,该技术的原理是将中断处理程序人为的分为两部分,上半部分是实时性要求较高的任务,后半部分可以稍后完成,这样就可以节省中断程序的处理时间。可整体的提高系统的性能。该技术将会在后续的博文中详细分析。

 

我们从上一篇分析中知道,在网络栈初始化的时候,已经将NET的下半部分执行函数定义成了net_bh(在socket.c文件中1375行左右)

 

[cpp] view plaincopy
 
  1. bh_base[NET_BH].routine= net_bh;//设置NET 下半部分的处理函数为net_bh  


* 函数net_bh的实现在net/inet/dev.c中

 

 

[cpp] view plaincopy
 
  1. /* 
  2.  *  When we are called the queue is ready to grab, the interrupts are 
  3.  *  on and hardware can interrupt and queue to the receive queue a we 
  4.  *  run with no problems. 
  5.  *  This is run as a bottom half after an interrupt handler that does 
  6.  *  mark_bh(NET_BH); 
  7.  */  
  8.    
  9. void net_bh(void *tmp)  
  10. {  
  11.     struct sk_buff *skb;  
  12.     struct packet_type *ptype;  
  13.     struct packet_type *pt_prev;  
  14.     unsigned short type;  
  15.   
  16.     /* 
  17.      *  Atomically check and mark our BUSY state.  
  18.      */  
  19.   
  20.     if (set_bit(1, (void*)&in_bh))//标记BUSY状态  
  21.         return;  
  22.   
  23.     /* 
  24.      *  Can we send anything now? We want to clear the 
  25.      *  decks for any more sends that get done as we 
  26.      *  process the input. 
  27.      */  
  28.   
  29.     dev_transmit();//调用dev_tinit()函数发送数据  
  30.     
  31.     /* 
  32.      *  Any data left to process. This may occur because a 
  33.      *  mark_bh() is done after we empty the queue including 
  34.      *  that from the device which does a mark_bh() just after 
  35.      */  
  36.   
  37.     cli();//防止队列操作错误,需要关中断和开中断  
  38.       
  39.     /* 
  40.      *  While the queue is not empty 
  41.      */  
  42.        
  43.     while((skb=skb_dequeue(&backlog))!=NULL)//出队直到队列为空  
  44.     {  
  45.         /* 
  46.          *  We have a packet. Therefore the queue has shrunk 
  47.          */  
  48.         backlog_size--;//队列元素个数减一  
  49.   
  50.         sti();  
  51.           
  52.            /* 
  53.         *   Bump the pointer to the next structure. 
  54.         *   This assumes that the basic 'skb' pointer points to 
  55.         *   the MAC header, if any (as indicated by its "length" 
  56.         *   field).  Take care now! 
  57.         */  
  58.   
  59.         skb->h.raw = skb->data + skb->dev->hard_header_len;  
  60.         skb->len -= skb->dev->hard_header_len;  
  61.   
  62.            /* 
  63.         *   Fetch the packet protocol ID.  This is also quite ugly, as 
  64.         *   it depends on the protocol driver (the interface itself) to 
  65.         *   know what the type is, or where to get it from.  The Ethernet 
  66.         *   interfaces fetch the ID from the two bytes in the Ethernet MAC 
  67.         *   header (the h_proto field in struct ethhdr), but other drivers 
  68.         *   may either use the ethernet ID's or extra ones that do not 
  69.         *   clash (eg ETH_P_AX25). We could set this before we queue the 
  70.         *   frame. In fact I may change this when I have time. 
  71.         */  
  72.           
  73.         type = skb->dev->type_trans(skb, skb->dev);//取出该数据包所属的协议类型  
  74.   
  75.         /* 
  76.          *  We got a packet ID.  Now loop over the "known protocols" 
  77.          *  table (which is actually a linked list, but this will 
  78.          *  change soon if I get my way- FvK), and forward the packet 
  79.          *  to anyone who wants it. 
  80.          * 
  81.          *  [FvK didn't get his way but he is right this ought to be 
  82.          *  hashed so we typically get a single hit. The speed cost 
  83.          *  here is minimal but no doubt adds up at the 4,000+ pkts/second 
  84.          *  rate we can hit flat out] 
  85.          */  
  86.         pt_prev = NULL;  
  87.         for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) //遍历ptype_base所指向的网络协议队列  
  88.         {  
  89.             //判断协议号是否匹配  
  90.             if ((ptype->type == type || ptype->type == htons(ETH_P_ALL)) && (!ptype->dev || ptype->dev==skb->dev))  
  91.             {  
  92.                 /* 
  93.                  *  We already have a match queued. Deliver 
  94.                  *  to it and then remember the new match 
  95.                  */  
  96.                 if(pt_prev)  
  97.                 {  
  98.                     struct sk_buff *skb2;  
  99.   
  100.                     skb2=skb_clone(skb, GFP_ATOMIC);//复制数据包结构  
  101.   
  102.                     /* 
  103.                      *  Kick the protocol handler. This should be fast 
  104.                      *  and efficient code. 
  105.                      */  
  106.   
  107.                     if(skb2)  
  108.                         pt_prev->func(skb2, skb->dev, pt_prev);//调用相应协议的处理函数,  
  109.                                             //这里和网络协议的种类有关系  
  110.                                             //如IP 协议的处理函数就是ip_rcv  
  111.                 }  
  112.                 /* Remember the current last to do */  
  113.                 pt_prev=ptype;  
  114.             }  
  115.         } /* End of protocol list loop */  
  116.           
  117.         /* 
  118.          *  Is there a last item to send to ? 
  119.          */  
  120.   
  121.         if(pt_prev)  
  122.             pt_prev->func(skb, skb->dev, pt_prev);  
  123.         /* 
  124.          *  Has an unknown packet has been received ? 
  125.          */  
  126.        
  127.         else  
  128.             kfree_skb(skb, FREE_WRITE);  
  129.   
  130.         /* 
  131.          *  Again, see if we can transmit anything now.  
  132.          *  [Ought to take this out judging by tests it slows 
  133.          *   us down not speeds us up] 
  134.          */  
  135.   
  136.         dev_transmit();  
  137.         cli();  
  138.     }   /* End of queue loop */  
  139.       
  140.     /* 
  141.      *  We have emptied the queue 
  142.      */  
  143.        
  144.     in_bh = 0;//BUSY状态还原  
  145.     sti();  
  146.       
  147.     /* 
  148.      *  One last output flush. 
  149.      */  
  150.        
  151.     dev_transmit();//清空缓冲区  
  152. }  

 

 

2、网络层
* 就以IP数据包为例来说明,那么从链路层向网络层传递时将调用ip_rcv函数。该函数完成本层的处理后会根据IP首部中使用的传输层协议来调用相应协议的处理函数。

UDP对应udp_rcv、TCP对应tcp_rcv、ICMP对应icmp_rcv、IGMP对应igmp_rcv(虽然这里的ICMP,IGMP一般成为网络层协议,但是实际上他们都封装在IP协议里面,作为传输层对待)

这个函数比较复杂,后续会详细分析。这里粘贴一下,让我们对整体了解更清楚

 

[cpp] view plaincopy
 
  1. /* 
  2.  *  This function receives all incoming IP datagrams. 
  3.  */  
  4.   
  5. int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)  
  6. {  
  7.     struct iphdr *iph = skb->h.iph;  
  8.     struct sock *raw_sk=NULL;  
  9.     unsigned char hash;  
  10.     unsigned char flag = 0;  
  11.     unsigned char opts_p = 0;   /* Set iff the packet has options. */  
  12.     struct inet_protocol *ipprot;  
  13.     static struct options opt; /* since we don't use these yet, and they 
  14.                 take up stack space. */  
  15.     int brd=IS_MYADDR;  
  16.     int is_frag=0;  
  17. #ifdef CONFIG_IP_FIREWALL  
  18.     int err;  
  19. #endif    
  20.   
  21.     ip_statistics.IpInReceives++;  
  22.   
  23.     /* 
  24.      *  Tag the ip header of this packet so we can find it 
  25.      */  
  26.   
  27.     skb->ip_hdr = iph;  
  28.   
  29.     /* 
  30.      *  Is the datagram acceptable? 
  31.      * 
  32.      *  1.  Length at least the size of an ip header 
  33.      *  2.  Version of 4 
  34.      *  3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums] 
  35.      *  (4. We ought to check for IP multicast addresses and undefined types.. does this matter ?) 
  36.      */  
  37.   
  38.     if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 ||  
  39.         skb->len<ntohs(iph->tot_len) || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)  
  40.     {  
  41.         ip_statistics.IpInHdrErrors++;  
  42.         kfree_skb(skb, FREE_WRITE);  
  43.         return(0);  
  44.     }  
  45.       
  46.     /* 
  47.      *  See if the firewall wants to dispose of the packet.  
  48.      */  
  49.   
  50. #ifdef  CONFIG_IP_FIREWALL  
  51.       
  52.     if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy, 0))!=1)  
  53.     {  
  54.         if(err==-1)  
  55.             icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);  
  56.         kfree_skb(skb, FREE_WRITE);  
  57.         return 0;     
  58.     }  
  59.   
  60. #endif  
  61.       
  62.     /* 
  63.      *  Our transport medium may have padded the buffer out. Now we know it 
  64.      *  is IP we can trim to the true length of the frame. 
  65.      */  
  66.   
  67.     skb->len=ntohs(iph->tot_len);  
  68.   
  69.     /* 
  70.      *  Next analyse the packet for options. Studies show under one packet in 
  71.      *  a thousand have options.... 
  72.      */  
  73.   
  74.     if (iph->ihl != 5)  
  75.     {   /* Fast path for the typical optionless IP packet. */  
  76.         memset((char *) &opt, 0, sizeof(opt));  
  77.         if (do_options(iph, &opt) != 0)  
  78.             return 0;  
  79.         opts_p = 1;  
  80.     }  
  81.   
  82.     /* 
  83.      *  Remember if the frame is fragmented. 
  84.      */  
  85.        
  86.     if(iph->frag_off)  
  87.     {  
  88.         if (iph->frag_off & 0x0020)  
  89.             is_frag|=1;  
  90.         /* 
  91.          *  Last fragment ? 
  92.          */  
  93.       
  94.         if (ntohs(iph->frag_off) & 0x1fff)  
  95.             is_frag|=2;  
  96.     }  
  97.       
  98.     /* 
  99.      *  Do any IP forwarding required.  chk_addr() is expensive -- avoid it someday. 
  100.      * 
  101.      *  This is inefficient. While finding out if it is for us we could also compute 
  102.      *  the routing table entry. This is where the great unified cache theory comes 
  103.      *  in as and when someone implements it 
  104.      * 
  105.      *  For most hosts over 99% of packets match the first conditional 
  106.      *  and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at 
  107.      *  function entry. 
  108.      */  
  109.   
  110.     if ( iph->daddr != skb->dev->pa_addr && (brd = ip_chk_addr(iph->daddr)) == 0)  
  111.     {  
  112.         /* 
  113.          *  Don't forward multicast or broadcast frames. 
  114.          */  
  115.   
  116.         if(skb->pkt_type!=PACKET_HOST || brd==IS_BROADCAST)  
  117.         {  
  118.             kfree_skb(skb,FREE_WRITE);  
  119.             return 0;  
  120.         }  
  121.   
  122.         /* 
  123.          *  The packet is for another target. Forward the frame 
  124.          */  
  125.   
  126. #ifdef CONFIG_IP_FORWARD  
  127.         ip_forward(skb, dev, is_frag);  
  128. #else  
  129. /*      printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", 
  130.             iph->saddr,iph->daddr);*/  
  131.         ip_statistics.IpInAddrErrors++;  
  132. #endif  
  133.         /* 
  134.          *  The forwarder is inefficient and copies the packet. We 
  135.          *  free the original now. 
  136.          */  
  137.   
  138.         kfree_skb(skb, FREE_WRITE);  
  139.         return(0);  
  140.     }  
  141.       
  142. #ifdef CONFIG_IP_MULTICAST    
  143.   
  144.     if(brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK))  
  145.     {  
  146.         /* 
  147.          *  Check it is for one of our groups 
  148.          */  
  149.         struct ip_mc_list *ip_mc=dev->ip_mc_list;  
  150.         do  
  151.         {  
  152.             if(ip_mc==NULL)  
  153.             {     
  154.                 kfree_skb(skb, FREE_WRITE);  
  155.                 return 0;  
  156.             }  
  157.             if(ip_mc->multiaddr==iph->daddr)  
  158.                 break;  
  159.             ip_mc=ip_mc->next;  
  160.         }  
  161.         while(1);  
  162.     }  
  163. #endif  
  164.     /* 
  165.      *  Account for the packet 
  166.      */  
  167.        
  168. #ifdef CONFIG_IP_ACCT  
  169.     ip_acct_cnt(iph,dev, ip_acct_chain);  
  170. #endif    
  171.   
  172.     /* 
  173.      * Reassemble IP fragments. 
  174.      */  
  175.   
  176.     if(is_frag)  
  177.     {  
  178.         /* Defragment. Obtain the complete packet if there is one */  
  179.         skb=ip_defrag(iph,skb,dev);  
  180.         if(skb==NULL)  
  181.             return 0;  
  182.         skb->dev = dev;  
  183.         iph=skb->h.iph;  
  184.     }  
  185.       
  186.            
  187.   
  188.     /* 
  189.      *  Point into the IP datagram, just past the header. 
  190.      */  
  191.   
  192.     skb->ip_hdr = iph;  
  193.     skb->h.raw += iph->ihl*4;  
  194.       
  195.     /* 
  196.      *  Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies. 
  197.      */  
  198.        
  199.     hash = iph->protocol & (SOCK_ARRAY_SIZE-1);  
  200.       
  201.     /* If there maybe a raw socket we must check - if not we don't care less */  
  202.     if((raw_sk=raw_prot.sock_array[hash])!=NULL)  
  203.     {  
  204.         struct sock *sknext=NULL;  
  205.         struct sk_buff *skb1;  
  206.         raw_sk=get_sock_raw(raw_sk, hash,  iph->saddr, iph->daddr);  
  207.         if(raw_sk)  /* Any raw sockets */  
  208.         {  
  209.             do  
  210.             {  
  211.                 /* Find the next */  
  212.                 sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr);  
  213.                 if(sknext)  
  214.                     skb1=skb_clone(skb, GFP_ATOMIC);  
  215.                 else  
  216.                     break;  /* One pending raw socket left */  
  217.                 if(skb1)  
  218.                     raw_rcv(raw_sk, skb1, dev, iph->saddr,iph->daddr);  
  219.                 raw_sk=sknext;  
  220.             }  
  221.             while(raw_sk!=NULL);  
  222.             /* Here either raw_sk is the last raw socket, or NULL if none */  
  223.             /* We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy */  
  224.         }  
  225.     }  
  226.       
  227.     /* 
  228.      *  skb->h.raw now points at the protocol beyond the IP header. 
  229.      */  
  230.   
  231.     hash = iph->protocol & (MAX_INET_PROTOS -1);  
  232.     for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)  
  233.     {  
  234.         struct sk_buff *skb2;  
  235.   
  236.         if (ipprot->protocol != iph->protocol)  
  237.             continue;  
  238.        /* 
  239.     *   See if we need to make a copy of it.  This will 
  240.     *   only be set if more than one protocol wants it. 
  241.     *   and then not for the last one. If there is a pending 
  242.     *   raw delivery wait for that 
  243.     */  
  244.         if (ipprot->copy || raw_sk)  
  245.         {  
  246.             skb2 = skb_clone(skb, GFP_ATOMIC);  
  247.             if(skb2==NULL)  
  248.                 continue;  
  249.         }  
  250.         else  
  251.         {  
  252.             skb2 = skb;  
  253.         }  
  254.         flag = 1;  
  255.   
  256.            /* 
  257.         * Pass on the datagram to each protocol that wants it, 
  258.         * based on the datagram protocol.  We should really 
  259.         * check the protocol handler's return values here... 
  260.         */  
  261.         ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,  
  262.                 (ntohs(iph->tot_len) - (iph->ihl * 4)),  
  263.                 iph->saddr, 0, ipprot);  
  264.   
  265.     }  
  266.   
  267.     /* 
  268.      * All protocols checked. 
  269.      * If this packet was a broadcast, we may *not* reply to it, since that 
  270.      * causes (proven, grin) ARP storms and a leakage of memory (i.e. all 
  271.      * ICMP reply messages get queued up for transmission...) 
  272.      */  
  273.   
  274.     if(raw_sk!=NULL)    /* Shift to last raw user */  
  275.         raw_rcv(raw_sk, skb, dev, iph->saddr, iph->daddr);  
  276.     else if (!flag)     /* Free and report errors */  
  277.     {  
  278.         if (brd != IS_BROADCAST && brd!=IS_MULTICAST)  
  279.             icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0, dev);  
  280.         kfree_skb(skb, FREE_WRITE);  
  281.     }  
  282.   
  283.     return(0);  
  284. }  


3、传输层

 

如果在IP数据报的首部标明的是使用TCP传输数据,则在上述函数中会调用tcp_rcv函数。该函数的大体处理流程为:

“所有使用TCP 协议的套接字对应sock 结构都被挂入tcp_prot 全局变量表示的proto 结构之sock_array 数组中,采用以本地端口号为索引的插入方式,所以当tcp_rcv 函数接收到一个数据包,在完成必要的检查和处理后,其将以TCP 协议首部中目的端口号(对于一个接收的数据包而言,其目的端口号就是本地所使用的端口号)为索引,在tcp_prot 对应sock 结构之sock_array 数组中得到正确的sock 结构队列,在辅之以其他条件遍历该队列进行对应sock 结构的查询,在得到匹配的sock 结构后,将数据包挂入该sock 结构中的缓存队列中(由sock 结构中receive_queue 字段指向),从而完成数据包的最终接收。”

该函数的实现也会比较复杂,这是由TCP协议的复杂功能决定的。附代码如下:

 

[cpp] view plaincopy
 
  1. /* 
  2.  *  A TCP packet has arrived. 
  3.  */  
  4.    
  5. int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,  
  6.     unsigned long daddr, unsigned short len,  
  7.     unsigned long saddr, int redo, struct inet_protocol * protocol)  
  8. {  
  9.     struct tcphdr *th;  
  10.     struct sock *sk;  
  11.     int syn_ok=0;  
  12.       
  13.     if (!skb)   
  14.     {  
  15.         printk("IMPOSSIBLE 1\n");  
  16.         return(0);  
  17.     }  
  18.   
  19.     if (!dev)   
  20.     {  
  21.         printk("IMPOSSIBLE 2\n");  
  22.         return(0);  
  23.     }  
  24.     
  25.     tcp_statistics.TcpInSegs++;  
  26.     
  27.     if(skb->pkt_type!=PACKET_HOST)  
  28.     {  
  29.         kfree_skb(skb,FREE_READ);  
  30.         return(0);  
  31.     }  
  32.     
  33.     th = skb->h.th;  
  34.   
  35.     /* 
  36.      *  Find the socket. 
  37.      */  
  38.   
  39.     sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);  
  40.   
  41.     /* 
  42.      *  If this socket has got a reset it's to all intents and purposes  
  43.      *  really dead. Count closed sockets as dead. 
  44.      * 
  45.      *  Note: BSD appears to have a bug here. A 'closed' TCP in BSD 
  46.      *  simply drops data. This seems incorrect as a 'closed' TCP doesn't 
  47.      *  exist so should cause resets as if the port was unreachable. 
  48.      */  
  49.        
  50.     if (sk!=NULL && (sk->zapped || sk->state==TCP_CLOSE))  
  51.         sk=NULL;  
  52.   
  53.     if (!redo)   
  54.     {  
  55.         if (tcp_check(th, len, saddr, daddr ))   
  56.         {  
  57.             skb->sk = NULL;  
  58.             kfree_skb(skb,FREE_READ);  
  59.             /* 
  60.              *  We don't release the socket because it was 
  61.              *  never marked in use. 
  62.              */  
  63.             return(0);  
  64.         }  
  65.         th->seq = ntohl(th->seq);  
  66.   
  67.         /* See if we know about the socket. */  
  68.         if (sk == NULL)   
  69.         {  
  70.             /* 
  71.              *  No such TCB. If th->rst is 0 send a reset (checked in tcp_reset) 
  72.              */  
  73.             tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);  
  74.             skb->sk = NULL;  
  75.             /* 
  76.              *  Discard frame 
  77.              */  
  78.             kfree_skb(skb, FREE_READ);  
  79.             return(0);  
  80.         }  
  81.   
  82.         skb->len = len;  
  83.         skb->acked = 0;  
  84.         skb->used = 0;  
  85.         skb->free = 0;  
  86.         skb->saddr = daddr;  
  87.         skb->daddr = saddr;  
  88.       
  89.         /* We may need to add it to the backlog here. */  
  90.         cli();  
  91.         if (sk->inuse)   
  92.         {  
  93.             skb_queue_tail(&sk->back_log, skb);  
  94.             sti();  
  95.             return(0);  
  96.         }  
  97.         sk->inuse = 1;  
  98.         sti();  
  99.     }  
  100.     else  
  101.     {  
  102.         if (sk==NULL)   
  103.         {  
  104.             tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);  
  105.             skb->sk = NULL;  
  106.             kfree_skb(skb, FREE_READ);  
  107.             return(0);  
  108.         }  
  109.     }  
  110.   
  111.   
  112.     if (!sk->prot)   
  113.     {  
  114.         printk("IMPOSSIBLE 3\n");  
  115.         return(0);  
  116.     }  
  117.   
  118.   
  119.     /* 
  120.      *  Charge the memory to the socket.  
  121.      */  
  122.        
  123.     if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)   
  124.     {  
  125.         kfree_skb(skb, FREE_READ);  
  126.         release_sock(sk);  
  127.         return(0);  
  128.     }  
  129.   
  130.     skb->sk=sk;  
  131.     sk->rmem_alloc += skb->mem_len;  
  132.   
  133.     /* 
  134.      *  This basically follows the flow suggested by RFC793, with the corrections in RFC1122. We 
  135.      *  don't implement precedence and we process URG incorrectly (deliberately so) for BSD bug 
  136.      *  compatibility. We also set up variables more thoroughly [Karn notes in the 
  137.      *  KA9Q code the RFC793 incoming segment rules don't initialise the variables for all paths]. 
  138.      */  
  139.   
  140.     if(sk->state!=TCP_ESTABLISHED)       /* Skip this lot for normal flow */  
  141.     {  
  142.       
  143.         /* 
  144.          *  Now deal with unusual cases. 
  145.          */  
  146.        
  147.         if(sk->state==TCP_LISTEN)  
  148.         {  
  149.             if(th->ack)  /* These use the socket TOS.. might want to be the received TOS */  
  150.                 tcp_reset(daddr,saddr,th,sk->prot,opt,dev,sk->ip_tos, sk->ip_ttl);  
  151.   
  152.             /* 
  153.              *  We don't care for RST, and non SYN are absorbed (old segments) 
  154.              *  Broadcast/multicast SYN isn't allowed. Note - bug if you change the 
  155.              *  netmask on a running connection it can go broadcast. Even Sun's have 
  156.              *  this problem so I'm ignoring it  
  157.              */  
  158.                  
  159.             if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR)  
  160.             {  
  161.                 kfree_skb(skb, FREE_READ);  
  162.                 release_sock(sk);  
  163.                 return 0;  
  164.             }  
  165.           
  166.             /*   
  167.              *  Guess we need to make a new socket up  
  168.              */  
  169.           
  170.             tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq());  
  171.           
  172.             /* 
  173.              *  Now we have several options: In theory there is nothing else 
  174.              *  in the frame. KA9Q has an option to send data with the syn, 
  175.              *  BSD accepts data with the syn up to the [to be] advertised window 
  176.              *  and Solaris 2.1 gives you a protocol error. For now we just ignore 
  177.              *  it, that fits the spec precisely and avoids incompatibilities. It 
  178.              *  would be nice in future to drop through and process the data. 
  179.              */  
  180.                
  181.             release_sock(sk);  
  182.             return 0;  
  183.         }  
  184.       
  185.         /* retransmitted SYN? */  
  186.         if (sk->state == TCP_SYN_RECV && th->syn && th->seq+1 == sk->acked_seq)  
  187.         {  
  188.             kfree_skb(skb, FREE_READ);  
  189.             release_sock(sk);  
  190.             return 0;  
  191.         }  
  192.           
  193.         /* 
  194.          *  SYN sent means we have to look for a suitable ack and either reset 
  195.          *  for bad matches or go to connected  
  196.          */  
  197.          
  198.         if(sk->state==TCP_SYN_SENT)  
  199.         {  
  200.             /* Crossed SYN or previous junk segment */  
  201.             if(th->ack)  
  202.             {  
  203.                 /* We got an ack, but it's not a good ack */  
  204.                 if(!tcp_ack(sk,th,saddr,len))  
  205.                 {  
  206.                     /* Reset the ack - its an ack from a  
  207.                        different connection  [ th->rst is checked in tcp_reset()] */  
  208.                     tcp_statistics.TcpAttemptFails++;  
  209.                     tcp_reset(daddr, saddr, th,  
  210.                         sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);  
  211.                     kfree_skb(skb, FREE_READ);  
  212.                     release_sock(sk);  
  213.                     return(0);  
  214.                 }  
  215.                 if(th->rst)  
  216.                     return tcp_std_reset(sk,skb);  
  217.                 if(!th->syn)  
  218.                 {  
  219.                     /* A valid ack from a different connection 
  220.                        start. Shouldn't happen but cover it */  
  221.                     kfree_skb(skb, FREE_READ);  
  222.                     release_sock(sk);  
  223.                     return 0;  
  224.                 }  
  225.                 /* 
  226.                  *  Ok.. it's good. Set up sequence numbers and 
  227.                  *  move to established. 
  228.                  */  
  229.                 syn_ok=1;   /* Don't reset this connection for the syn */  
  230.                 sk->acked_seq=th->seq+1;  
  231.                 sk->fin_seq=th->seq;  
  232.                 tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr);  
  233.                 tcp_set_state(sk, TCP_ESTABLISHED);  
  234.                 tcp_options(sk,th);  
  235.                 sk->dummy_th.dest=th->source;  
  236.                 sk->copied_seq = sk->acked_seq;  
  237.                 if(!sk->dead)  
  238.                 {  
  239.                     sk->state_change(sk);  
  240.                     sock_wake_async(sk->socket, 0);  
  241.                 }  
  242.                 if(sk->max_window==0)  
  243.                 {  
  244.                     sk->max_window = 32;  
  245.                     sk->mss = min(sk->max_window, sk->mtu);  
  246.                 }  
  247.             }  
  248.             else  
  249.             {  
  250.                 /* See if SYN's cross. Drop if boring */  
  251.                 if(th->syn && !th->rst)  
  252.                 {  
  253.                     /* Crossed SYN's are fine - but talking to 
  254.                        yourself is right out... */  
  255.                     if(sk->saddr==saddr && sk->daddr==daddr &&  
  256.                         sk->dummy_th.source==th->source &&  
  257.                         sk->dummy_th.dest==th->dest)  
  258.                     {  
  259.                         tcp_statistics.TcpAttemptFails++;  
  260.                         return tcp_std_reset(sk,skb);  
  261.                     }  
  262.                     tcp_set_state(sk,TCP_SYN_RECV);  
  263.                       
  264.                     /* 
  265.                      *  FIXME: 
  266.                      *  Must send SYN|ACK here 
  267.                      */  
  268.                 }         
  269.                 /* Discard junk segment */  
  270.                 kfree_skb(skb, FREE_READ);  
  271.                 release_sock(sk);  
  272.                 return 0;  
  273.             }  
  274.             /* 
  275.              *  SYN_RECV with data maybe.. drop through 
  276.              */  
  277.             goto rfc_step6;  
  278.         }  
  279.   
  280.     /* 
  281.      *  BSD has a funny hack with TIME_WAIT and fast reuse of a port. There is 
  282.      *  a more complex suggestion for fixing these reuse issues in RFC1644 
  283.      *  but not yet ready for general use. Also see RFC1379. 
  284.      */  
  285.       
  286. #define BSD_TIME_WAIT  
  287. #ifdef BSD_TIME_WAIT  
  288.         if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead &&   
  289.             after(th->seq, sk->acked_seq) && !th->rst)  
  290.         {  
  291.             long seq=sk->write_seq;  
  292.             if(sk->debug)  
  293.                 printk("Doing a BSD time wait\n");  
  294.             tcp_statistics.TcpEstabResets++;         
  295.             sk->rmem_alloc -= skb->mem_len;  
  296.             skb->sk = NULL;  
  297.             sk->err=ECONNRESET;  
  298.             tcp_set_state(sk, TCP_CLOSE);  
  299.             sk->shutdown = SHUTDOWN_MASK;  
  300.             release_sock(sk);  
  301.             sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);  
  302.             if (sk && sk->state==TCP_LISTEN)  
  303.             {  
  304.                 sk->inuse=1;  
  305.                 skb->sk = sk;  
  306.                 sk->rmem_alloc += skb->mem_len;  
  307.                 tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000);  
  308.                 release_sock(sk);  
  309.                 return 0;  
  310.             }  
  311.             kfree_skb(skb, FREE_READ);  
  312.             return 0;  
  313.         }  
  314. #endif    
  315.     }  
  316.   
  317.     /* 
  318.      *  We are now in normal data flow (see the step list in the RFC) 
  319.      *  Note most of these are inline now. I'll inline the lot when 
  320.      *  I have time to test it hard and look at what gcc outputs  
  321.      */  
  322.       
  323.     if(!tcp_sequence(sk,th,len,opt,saddr,dev))  
  324.     {  
  325.         kfree_skb(skb, FREE_READ);  
  326.         release_sock(sk);  
  327.         return 0;  
  328.     }  
  329.   
  330.     if(th->rst)  
  331.         return tcp_std_reset(sk,skb);  
  332.       
  333.     /* 
  334.      *  !syn_ok is effectively the state test in RFC793. 
  335.      */  
  336.        
  337.     if(th->syn && !syn_ok)  
  338.     {  
  339.         tcp_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255);  
  340.         return tcp_std_reset(sk,skb);     
  341.     }  
  342.   
  343.     /* 
  344.      *  Process the ACK 
  345.      */  
  346.        
  347.   
  348.     if(th->ack && !tcp_ack(sk,th,saddr,len))  
  349.     {  
  350.         /* 
  351.          *  Our three way handshake failed. 
  352.          */  
  353.            
  354.         if(sk->state==TCP_SYN_RECV)  
  355.         {  
  356.             tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);  
  357.         }  
  358.         kfree_skb(skb, FREE_READ);  
  359.         release_sock(sk);  
  360.         return 0;  
  361.     }  
  362.       
  363. rfc_step6:      /* I'll clean this up later */  
  364.   
  365.     /* 
  366.      *  Process urgent data 
  367.      */  
  368.           
  369.     if(tcp_urg(sk, th, saddr, len))  
  370.     {  
  371.         kfree_skb(skb, FREE_READ);  
  372.         release_sock(sk);  
  373.         return 0;  
  374.     }  
  375.       
  376.       
  377.     /* 
  378.      *  Process the encapsulated data 
  379.      */  
  380.       
  381.     if(tcp_data(skb,sk, saddr, len))  
  382.     {  
  383.         kfree_skb(skb, FREE_READ);  
  384.         release_sock(sk);  
  385.         return 0;  
  386.     }  
  387.   
  388.     /* 
  389.      *  And done 
  390.      */   
  391.       
  392.     release_sock(sk);  
  393.     return 0;  
  394. }  


4、应用层

 

当用户需要接收数据时,首先根据文件描述符inode得到socket结构和sock结构,然后从sock结构中指向的队列recieve_queue中读取数据包,将数据包COPY到用户空间缓冲区。数据就完整的从硬件中传输到用户空间。这样也完成了一次完整的从下到上的传输。

 

下篇:

在博文Linux内核--网络栈实现分析(二)--数据包的传递过程(上)中分析了数据包从网卡设备经过驱动链路层,网络层,传输层到应用层的过程。

本文就分析一下本机产生数据是如何通过传输层,网络层到达物理层的。

综述来说,数据流程图如下:

一、应用层

应用层可以通过系统调用或文件操作来调用内核函数,BSD层的sock_write()函数会调用INET层的inet_wirte()函数。

 

[cpp] view plaincopy
 
  1. /* 
  2.  *  Write data to a socket. We verify that the user area ubuf..ubuf+size-1 is 
  3.  *  readable by the user process. 
  4.  */  
  5.   
  6. static int sock_write(struct inode *inode, struct file *file, char *ubuf, int size)  
  7. {  
  8.     struct socket *sock;  
  9.     int err;  
  10.       
  11.     if (!(sock = socki_lookup(inode)))   
  12.     {  
  13.         printk("NET: sock_write: can't find socket for inode!\n");  
  14.         return(-EBADF);  
  15.     }  
  16.   
  17.     if (sock->flags & SO_ACCEPTCON)   
  18.         return(-EINVAL);  
  19.       
  20.     if(size<0)  
  21.         return -EINVAL;  
  22.     if(size==0)  
  23.         return 0;  
  24.           
  25.     if ((err=verify_area(VERIFY_READ,ubuf,size))<0)  
  26.         return err;  
  27.     return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK)));  
  28. }  


INET层会调用具体传输层协议的write函数,该函数是通过调用本层的inet_send()函数实现功能的,inet_send()函数的UDP协议对应的函数为udp_write()

 

 

[cpp] view plaincopy
 
  1. static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,   
  2.            unsigned flags)  
  3. {  
  4.     struct sock *sk = (struct sock *) sock->data;  
  5.     if (sk->shutdown & SEND_SHUTDOWN)   
  6.     {  
  7.         send_sig(SIGPIPE, current, 1);  
  8.         return(-EPIPE);  
  9.     }  
  10.     if(sk->err)  
  11.         return inet_error(sk);  
  12.     /* We may need to bind the socket. */  
  13.     if(inet_autobind(sk)!=0)  
  14.         return(-EAGAIN);  
  15.     return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));  
  16. }  
  17.   
  18. static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)  
  19. {  
  20.     return inet_send(sock,ubuf,size,noblock,0);  
  21. }  

 

二、传输层

 

在传输层udp_write()函数调用本层的udp_sendto()函数完成功能。

 

[cpp] view plaincopy
 
  1. /* 
  2.  *  In BSD SOCK_DGRAM a write is just like a send. 
  3.  */  
  4.   
  5. static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,  
  6.       unsigned flags)  
  7. {  
  8.     return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));  
  9. }  


udp_send()函数完成sk_buff结构相应的设置和报头的填写后会调用udp_send()来发送数据。具体的实现过程后面会详细分析。

 

而在udp_send()函数中,最后会调用ip_queue_xmit()函数,将数据包下放的网络层。

下面是udp_prot定义:

 

[cpp] view plaincopy
 
  1. struct proto udp_prot = {  
  2.     sock_wmalloc,  
  3.     sock_rmalloc,  
  4.     sock_wfree,  
  5.     sock_rfree,  
  6.     sock_rspace,  
  7.     sock_wspace,  
  8.     udp_close,  
  9.     udp_read,  
  10.     udp_write,  
  11.     udp_sendto,  
  12.     udp_recvfrom,  
  13.     ip_build_header,  
  14.     udp_connect,  
  15.     NULL,  
  16.     ip_queue_xmit,  
  17.     NULL,  
  18.     NULL,  
  19.     NULL,  
  20.     udp_rcv,  
  21.     datagram_select,  
  22.     udp_ioctl,  
  23.     NULL,  
  24.     NULL,  
  25.     ip_setsockopt,  
  26.     ip_getsockopt,  
  27.     128,  
  28.     0,  
  29.     {NULL,},  
  30.     "UDP",  
  31.     0, 0  
  32. };  

 

[cpp] view plaincopy
 
  1. static int udp_send(struct sock *sk, struct sockaddr_in *sin,  
  2.      unsigned char *from, int len, int rt)  
  3. {  
  4.     struct sk_buff *skb;  
  5.     struct device *dev;  
  6.     struct udphdr *uh;  
  7.     unsigned char *buff;  
  8.     unsigned long saddr;  
  9.     int size, tmp;  
  10.     int ttl;  
  11.     
  12.     /*  
  13.      *  Allocate an sk_buff copy of the packet. 
  14.      */  
  15.        
  16.     ........................  
  17.   
  18.     /* 
  19.      *  Now build the IP and MAC header.  
  20.      */  
  21.        
  22.     ..........................  
  23.     /* 
  24.      *  Fill in the UDP header.  
  25.      */  
  26.        
  27.     ..............................  
  28.   
  29.     /* 
  30.      *  Copy the user data.  
  31.      */  
  32.        
  33.     memcpy_fromfs(buff, from, len);  
  34.   
  35.     /* 
  36.      *  Set up the UDP checksum.  
  37.      */  
  38.        
  39.     udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);  
  40.   
  41.     /*  
  42.      *  Send the datagram to the interface.  
  43.      */  
  44.        
  45.     udp_statistics.UdpOutDatagrams++;  
  46.        
  47.     sk->prot->queue_xmit(sk, dev, skb, 1);  
  48.     return(len);  
  49. }  



 

三、网络层

 在网络层,函数ip_queue_xmit()的功能是将数据包进行一系列复杂的操作,比如是检查数据包是否需要分片,是否是多播等一系列检查,最后调用dev_queue_xmit()函数发送数据。

 

[cpp] view plaincopy
 
  1. /* 
  2.  * Queues a packet to be sent, and starts the transmitter 
  3.  * if necessary.  if free = 1 then we free the block after 
  4.  * transmit, otherwise we don't. If free==2 we not only 
  5.  * free the block but also don't assign a new ip seq number. 
  6.  * This routine also needs to put in the total length, 
  7.  * and compute the checksum 
  8.  */  
  9.   
  10. void ip_queue_xmit(struct sock *sk, struct device *dev,  
  11.           struct sk_buff *skb, int free)  
  12. {  
  13.     struct iphdr *iph;  
  14.     unsigned char *ptr;  
  15.   
  16.     /* Sanity check */  
  17.     ............  
  18.     /* 
  19.      *  Do some book-keeping in the packet for later 
  20.      */  
  21.   
  22.   
  23.     ...........  
  24.   
  25.     /* 
  26.      *  Find the IP header and set the length. This is bad 
  27.      *  but once we get the skb data handling code in the 
  28.      *  hardware will push its header sensibly and we will 
  29.      *  set skb->ip_hdr to avoid this mess and the fixed 
  30.      *  header length problem 
  31.      */  
  32.   
  33.     ..............  
  34.     /* 
  35.      *  No reassigning numbers to fragments... 
  36.      */  
  37.   
  38.     if(free!=2)  
  39.         iph->id      = htons(ip_id_count++);  
  40.     else  
  41.         free=1;  
  42.   
  43.     /* All buffers without an owner socket get freed */  
  44.     if (sk == NULL)  
  45.         free = 1;  
  46.   
  47.     skb->free = free;  
  48.   
  49.     /* 
  50.      *  Do we need to fragment. Again this is inefficient. 
  51.      *  We need to somehow lock the original buffer and use 
  52.      *  bits of it. 
  53.      */  
  54.   
  55.     ................  
  56.   
  57.     /* 
  58.      *  Add an IP checksum 
  59.      */  
  60.   
  61.     ip_send_check(iph);  
  62.   
  63.     /* 
  64.      *  Print the frame when debugging 
  65.      */  
  66.   
  67.     /* 
  68.      *  More debugging. You cannot queue a packet already on a list 
  69.      *  Spot this and moan loudly. 
  70.      */  
  71.     .......................  
  72.   
  73.     /* 
  74.      *  If a sender wishes the packet to remain unfreed 
  75.      *  we add it to his send queue. This arguably belongs 
  76.      *  in the TCP level since nobody else uses it. BUT 
  77.      *  remember IPng might change all the rules. 
  78.      */  
  79.   
  80.     ......................  
  81.     /* 
  82.      *  If the indicated interface is up and running, send the packet. 
  83.      */  
  84.        
  85.     ip_statistics.IpOutRequests++;  
  86.         .............................  
  87.     .............................  
  88.         if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))  
  89.         ip_loopback(dev,skb);  
  90.           
  91.     if (dev->flags & IFF_UP)  
  92.     {  
  93.         /* 
  94.          *  If we have an owner use its priority setting, 
  95.          *  otherwise use NORMAL 
  96.          */  
  97.   
  98.         if (sk != NULL)  
  99.         {  
  100.             dev_queue_xmit(skb, dev, sk->priority);  
  101.         }  
  102.         else  
  103.         {  
  104.             dev_queue_xmit(skb, dev, SOPRI_NORMAL);  
  105.         }  
  106.     }  
  107.     else  
  108.     {  
  109.         ip_statistics.IpOutDiscards++;  
  110.         if (free)  
  111.             kfree_skb(skb, FREE_WRITE);  
  112.     }  
  113. }  

 

四、驱动层(链路层)

在函数中,函数调用会调用具体设备的发送函数来发送数据包

dev->hard_start_xmit(skb, dev);

具体设备的发送函数在网络初始化的时候已经设置了。

这里以8390网卡为例来说明驱动层的工作原理,在net/drivers/8390.c中函数ethdev_init()函数中设置如下:

 

[cpp] view plaincopy
 
  1. /* Initialize the rest of the 8390 device structure. */  
  2. int ethdev_init(struct device *dev)  
  3. {  
  4.     if (ei_debug > 1)  
  5.         printk(version);  
  6.       
  7.     if (dev->priv == NULL) {//申请私有空间  
  8.         struct ei_device *ei_local;//8390网卡设备的结构体  
  9.           
  10.         dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);//申请内核内存空间  
  11.         memset(dev->priv, 0, sizeof(struct ei_device));  
  12.         ei_local = (struct ei_device *)dev->priv;  
  13. #ifndef NO_PINGPONG  
  14.         ei_local->pingpong = 1;  
  15. #endif  
  16.     }  
  17.       
  18.     /* The open call may be overridden by the card-specific code. */  
  19.     if (dev->open == NULL)  
  20.         dev->open = &ei_open;//设备的打开函数  
  21.     /* We should have a dev->stop entry also. */  
  22.     dev->hard_start_xmit = &ei_start_xmit;//设备的发送函数,定义在8390.c中  
  23.     dev->get_stats   = get_stats;  
  24. #ifdef HAVE_MULTICAST  
  25.     dev->set_multicast_list = &set_multicast_list;  
  26. #endif  
  27.   
  28.     ether_setup(dev);  
  29.           
  30.     return 0;  
  31. }  


驱动中的发送函数比较复杂,和硬件关系紧密,这里不再详细分析。

 

 

这样就大体分析了下网络数据从应用层到物理层的数据通路,后面会详细分析。

 

posted on 2014-03-16 22:46  一天不进步,就是退步  阅读(3321)  评论(0编辑  收藏  举报