Linux内核--网络栈实现分析(二)--数据包的传递过程--转


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

作者:闫明

本文分析基于Linux Kernel 1.2.13

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

上篇:

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

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

Linux内核--网络栈实现分析(二)--数据包的传递过程--转

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

Linux内核--网络栈实现分析(二)--数据包的传递过程--转

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

1、网络接口层

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

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

该函数的实现如下:

  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. void netif_rx(struct sk_buff *skb)
  9. {
  10. static int dropping = 0;
  11. /*
  12. *  Any received buffers are un-owned and should be discarded
  13. *  when freed. These will be updated later as the frames get
  14. *  owners.
  15. */
  16. skb->sk = NULL;
  17. skb->free = 1;
  18. if(skb->stamp.tv_sec==0)
  19. skb->stamp = xtime;
  20. /*
  21. *  Check that we aren't overdoing things.
  22. */
  23. if (!backlog_size)
  24. dropping = 0;
  25. else if (backlog_size > 300)
  26. dropping = 1;
  27. if (dropping)
  28. {
  29. kfree_skb(skb, FREE_READ);
  30. return;
  31. }
  32. /*
  33. *  Add it to the "backlog" queue.
  34. */
  35. #ifdef CONFIG_SKB_CHECK
  36. IS_SKB(skb);
  37. #endif
  38. skb_queue_tail(&backlog,skb);//加入队列backlog
  39. backlog_size++;
  40. /*
  41. *  If any packet arrived, mark it for processing after the
  42. *  hardware interrupt returns.
  43. */
  44. mark_bh(NET_BH);//下半部分bottom half技术可以减少中断处理程序的执行时间
  45. return;
  46. }

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

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

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

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

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

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

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

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

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

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协议的复杂功能决定的。附代码如下:

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

4、应用层

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

下篇:

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

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

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

Linux内核--网络栈实现分析(二)--数据包的传递过程--转

一、应用层

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

  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. static int sock_write(struct inode *inode, struct file *file, char *ubuf, int size)
  6. {
  7. struct socket *sock;
  8. int err;
  9. if (!(sock = socki_lookup(inode)))
  10. {
  11. printk("NET: sock_write: can't find socket for inode!\n");
  12. return(-EBADF);
  13. }
  14. if (sock->flags & SO_ACCEPTCON)
  15. return(-EINVAL);
  16. if(size<0)
  17. return -EINVAL;
  18. if(size==0)
  19. return 0;
  20. if ((err=verify_area(VERIFY_READ,ubuf,size))<0)
  21. return err;
  22. return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK)));
  23. }

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

  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. static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)
  18. {
  19. return inet_send(sock,ubuf,size,noblock,0);
  20. }

二、传输层

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

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

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

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

下面是udp_prot定义:

  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. };
  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. *  Allocate an sk_buff copy of the packet.
  13. */
  14. ........................
  15. /*
  16. *  Now build the IP and MAC header.
  17. */
  18. ..........................
  19. /*
  20. *  Fill in the UDP header.
  21. */
  22. ..............................
  23. /*
  24. *  Copy the user data.
  25. */
  26. memcpy_fromfs(buff, from, len);
  27. /*
  28. *  Set up the UDP checksum.
  29. */
  30. udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
  31. /*
  32. *  Send the datagram to the interface.
  33. */
  34. udp_statistics.UdpOutDatagrams++;
  35. sk->prot->queue_xmit(sk, dev, skb, 1);
  36. return(len);
  37. }

三、网络层

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

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

四、驱动层(链路层)

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

dev->hard_start_xmit(skb, dev);

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

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

  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. if (dev->priv == NULL) {//申请私有空间
  7. struct ei_device *ei_local;//8390网卡设备的结构体
  8. dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);//申请内核内存空间
  9. memset(dev->priv, 0, sizeof(struct ei_device));
  10. ei_local = (struct ei_device *)dev->priv;
  11. #ifndef NO_PINGPONG
  12. ei_local->pingpong = 1;
  13. #endif
  14. }
  15. /* The open call may be overridden by the card-specific code. */
  16. if (dev->open == NULL)
  17. dev->open = &ei_open;//设备的打开函数
  18. /* We should have a dev->stop entry also. */
  19. dev->hard_start_xmit = &ei_start_xmit;//设备的发送函数,定义在8390.c中
  20. dev->get_stats   = get_stats;
  21. #ifdef HAVE_MULTICAST
  22. dev->set_multicast_list = &set_multicast_list;
  23. #endif
  24. ether_setup(dev);
  25. return 0;
  26. }

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

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

上一篇:BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊(动态树)


下一篇:R语言中的横向数据合并merge及纵向数据合并rbind的使用