Chinaunix首页 | 论坛 | 博客
  • 博客访问: 972042
  • 博文数量: 58
  • 博客积分: 10192
  • 博客等级: 上将
  • 技术积分: 1845
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-22 21:24
文章分类

全部博文(58)

文章存档

2011年(11)

2010年(12)

2009年(20)

2008年(15)

分类: LINUX

2010-12-18 12:02:22

.数据包转发

1..转发就是把中转所有不是传给本地系统的输入数据包,把它们再次发送到目的地或者下一站路由。Linux下转发的接口是ip_forward函数。

 

  1. int ip_forward(struct sk_buff *skb)

  2. {

  3. struct iphdr *iph; /* Our header */

  4. struct rtable *rt; /* Route we use */

  5. struct ip_options * opt = &(IPCB(skb)->opt);


  6. if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))

  7. goto drop;


  8. if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))

  9. return NET_RX_SUCCESS;


  10. if (skb->pkt_type != PACKET_HOST)

  11. goto drop;


  12. skb->ip_summed = CHECKSUM_NONE;


  13. /*

  14.  * According to the RFC, we must first decrease the TTL field. If

  15.  * that reaches zero, we must reply an ICMP control message telling

  16.  * that the packet's lifetime expired.

  17.  */


  18. iph = skb->nh.iph;


  19. /*

  20.  * TTL减1等于0,则丢弃封包。

  21.  */

  22. if (iph->ttl <= 1)

  23.                 goto too_many_hops;


  24. if (!xfrm4_route_forward(skb))

  25. goto drop;


  26. iph = skb->nh.iph;

  27. rt = (struct rtable*)skb->dst;


  28. /*

  29.  * rt->rt_dst报头选项中存储的下一个跳点。

  30.  * rt->rt_gateway由路由子系统所找到的下一个跳点。

  31.  * 如果strict为真且上述两者不相等,则选项失败不能严格路由。

  32.  */

  33. if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)

  34. goto sr_failed;


  35. /* We are about to mangle packet. Copy it! */

  36. if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))

  37. goto drop;

  38. iph = skb->nh.iph;


  39. /* Decrease ttl after skb cow done */

  40. ip_decrease_ttl(iph);


  41. /*

  42.  * We now generate an ICMP HOST REDIRECT giving the route

  43.  * we calculated.

  44.  */

  45. /*

  46.  * 如果有比请求的还要好的下一个跳点话,源主机就会收到重定向的ICMP信息

  47.  * !opt->srr(srr表示是否请求过源路由)为false,

  48.  * 表明原主机不在乎是否有更好的路由被发现。

  49.  */

  50. if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)

  51. ip_rt_send_redirect(skb);

  52. /*

  53.  * 根据IP头部的TOS来设置优先级

  54.  * 该值将会在后面Traffic Control中使用

  55.  */

  56. skb->priority = rt_tos2priority(iph->tos);

  57.  /*

  58.   * 如果Netfilter没有禁止转发规则,

  59.   * 通过NF_HOOK来执行ip_forward_finish函数

  60.   */

  61. return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,

  62.        ip_forward_finish);


  63. sr_failed:

  64.         /*

  65.          * Strict routing permits no gatewaying

  66.          */

  67.          icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);

  68.          goto drop;


  69. too_many_hops:

  70.         /* Tell the sender its packet died... */

  71.         icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);

  72. drop:

  73. kfree_skb(skb);

  74. return NET_RX_DROP;

  75. }

 

2. ip_forward_finish函数:表明封包都已经检查完毕,可以传出。

 

  1. static inline int ip_forward_finish(struct sk_buff *skb)

  2. {

  3. struct ip_options * opt = &(IPCB(skb)->opt);


  4. IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS);


  5. if (unlikely(opt->optlen))

  6. /* RR,SRR选项的处理 */

  7. ip_forward_options(skb);

  8. /* 所有传输(本地产生或从其他主机转发而来)都是通过dst_output传出 */

  9. return dst_output(skb);

  10. }

 

3.调用dst_output函数把数据包传出。

 

  1. /* Output packet to network from transport. */


  2. static inline int dst_output(struct sk_buff *skb)


  3. {


  4. int err;




  5. for (;;) {


  6. /*

  7.  * 通过output来对封包进行传出。

  8.  * 如果目的地址是单播的话,output就等于ip_output 。

  9.  */

  10. err = skb->dst->output(skb);




  11. if (likely(err == 0))


  12. return err;


  13. if (unlikely(err != NET_XMIT_BYPASS))


  14. return err;


  15. }


  16. }

 

.数据包本地传递:

1.本地传递:本地主机地址就是封包的目的地。Linux下转发的接口是ip_local_deliver函数。

  1. /*


  2.  * Deliver IP Packets to the higher protocol layers.


  3.  */


  4. int ip_local_deliver(struct sk_buff *skb)


  5. {


  6. /*


  7.  * Reassemble IP fragments.


  8.                * 封包进入本地传递后,首先判断是否分片

  9.                * 如果是分片包,进行重组。

  10.  */


  11. if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {


  12. skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER);


  13. if (!skb)


  14. return 0;


  15. }



  16.               

  17. return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,


  18.        ip_local_deliver_finish);


  19. }
阅读(4095) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~