<Linux Network 2.6.38> "where_to_go"

来源:互联网 发布:淘宝如何设置免运费 编辑:程序博客网 时间:2024/04/29 02:04

http://sunzixun.iteye.com/blog/981310

先来回顾一个潜在的结构 在skb的 pskb_copy skb_copy  等操作中起到了关键作用

 

 写道
struct skb_shared_info {
unsigned short nr_frags;
unsigned short gso_size;
/* Warning: this field is not always filled in (UFO)! */
unsigned short gso_segs;
unsigned short gso_type;
__be32 ip6_frag_id;
__u8 tx_flags;
struct sk_buff *frag_list;
struct skb_shared_hwtstamps hwtstamps;
atomic_t dataref;
void * destructor_arg;
skb_frag_t frags[MAX_SKB_FRAGS];
};

 想要顺利的访问这个结构就要了解一个宏

 

#define skb_shinfo(SKB)             ((struct skb_shared_info *)((SKB)->end))

 

 

 

再回忆一下头部结构

 

 

 写道
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__sum16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
};
 

 

好了现在就看看, 上前天说到的 ip_rcv 如何Ip处理包

 

 

C代码  收藏代码
  1. int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)  
  2. {  
  3.     /*在sk_buff  __netif_receive_skb  eth_type_trans 中已经让包符合L3 */  
  4.     struct iphdr *iph;  
  5.     u32 len;  
  6.   
  7.     /*如果是因为开了promiscuous 模式而让垃圾包到了L3 ,就丢弃不属于自己的 */  
  8.     if (skb->pkt_type == PACKET_OTHERHOST)  
  9.         goto drop;  
  10.   
  11.     /*依旧SNMP 采集点*/  
  12.     IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len);  
  13.     /*如果这包在别的子系统也使用 就拷贝一份给自己专门用*/  
  14.     if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {  
  15.         IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);  
  16.         goto out;/*拷贝失败就丢弃*/  
  17.     }  
  18.     /*如果是分包的话 ,用__pskb_pull_tail把skb_shared_info中frag_list找回来 */  
  19.     if (!pskb_may_pull(skb, sizeof(struct iphdr)))  
  20.         goto inhdr_error;  
  21.     /*重新指向L3头部*/  
  22.     iph = ip_hdr(skb);  
  23.   
  24.     /* 
  25.      *  RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum. 
  26.      * 
  27.      *  Is the datagram acceptable? 
  28.      * 
  29.      *  1.  Length at least the size of an ip header 
  30.      *  2.  Version of 4 
  31.      *  3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums] 
  32.      *  4.  Doesn't have a bogus length 
  33.      */  
  34.     /*头部和版本检查*/  
  35.     if (iph->ihl < 5 || iph->version != 4)  
  36.         goto inhdr_error;  
  37.     /*同样的动作, 不过和上一次比这次是整个IP头部了*/  
  38.     if (!pskb_may_pull(skb, iph->ihl*4))  
  39.         goto inhdr_error;  
  40.   
  41.     iph = ip_hdr(skb);  
  42.     /*校验*/  
  43.     if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))  
  44.         goto inhdr_error;  
  45.     /*长度完整性校验*/  
  46.     len = ntohs(iph->tot_len);  
  47.     /*skb buffer的真实长度只能比包头报告的长度大<因为可能被L2层填充了>或正好,小的话就有问题咯*/  
  48.     if (skb->len < len) {  
  49.         IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);  
  50.         goto drop;  
  51.     } else if (len < (iph->ihl*4))  
  52.     /*包头可能比包体还长吗? :)*/  
  53.         goto inhdr_error;  
  54.   
  55.     /* Our transport medium may have padded the buffer out. Now we know it 
  56.      * is IP we can trim to the true length of the frame. 
  57.      * Note this now means skb->len holds ntohs(iph->tot_len). 
  58.      */  
  59.     /*被L2填充了吗? 去掉! 前面校验不算~*/  
  60.     if (pskb_trim_rcsum(skb, len)) {  
  61.         IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);  
  62.         goto drop;  
  63.     }  
  64.   
  65.     /* Remove any debris in the socket control block */  
  66.     /*看起来L3不需要 ip_options*/  
  67.     memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));  
  68.   
  69.     /* Must drop socket now because of tproxy. */  
  70.     /*既然都被我处理过了,就跟我把,帮你净身*/  
  71.     skb_orphan(skb);  
  72.     /*接受Netfilter 的洗礼吧(LVS基于此),最后再执行 ip_rcv_finish,这是正常之旅*/  
  73.     return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,  
  74.                ip_rcv_finish);  
  75.   
  76. inhdr_error:  
  77.     /*去MIB树上反应一下*/  
  78.     IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);  
  79. drop:  
  80.     kfree_skb(skb);  
  81. out:    /*哎*/  
  82.     return NET_RX_DROP;  
  83. }  

 

 接下来就是看看 ip_rcv_finish

 

 

 

C代码  收藏代码
  1. static int ip_rcv_finish(struct sk_buff *skb)  
  2. {  
  3.     const struct iphdr *iph = ip_hdr(skb);  
  4.     struct rtable *rt;  
  5.   
  6.     /* 
  7.      *  如果包中没有dst_entry结构(不知如何转发),就直接询问路由子系统看看有没人要它(后面就不处理了) 
  8.      */  
  9.     if (skb_dst(skb) == NULL) {  
  10.         int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,  
  11.                            iph->tos, skb->dev);  
  12.         if (unlikely(err)) {  
  13.             if (err == -EHOSTUNREACH)  
  14.                 IP_INC_STATS_BH(dev_net(skb->dev),  
  15.                         IPSTATS_MIB_INADDRERRORS);  
  16.             else if (err == -ENETUNREACH)  
  17.                 IP_INC_STATS_BH(dev_net(skb->dev),  
  18.                         IPSTATS_MIB_INNOROUTES);  
  19.             else if (err == -EXDEV)  
  20.                 NET_INC_STATS_BH(dev_net(skb->dev),  
  21.                          LINUX_MIB_IPRPFILTER);  
  22.             goto drop;  
  23.         }  
  24.     }  
  25. /*更新该CPU的ip_rt_acct 统计,参考/proc/net/rt_acct*/  
  26. #ifdef CONFIG_NET_CLS_ROUTE  
  27.     if (unlikely(skb_dst(skb)->tclassid)) {  
  28.         struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct);  
  29.         u32 idx = skb_dst(skb)->tclassid;  
  30.         st[idx&0xFF].o_packets++;  
  31.         st[idx&0xFF].o_bytes += skb->len;  
  32.         st[(idx>>16)&0xFF].i_packets++;  
  33.         st[(idx>>16)&0xFF].i_bytes += skb->len;  
  34.     }  
  35. #endif  
  36.     /*如果有IP options就去处理*/  
  37.     if (iph->ihl > 5 && ip_rcv_options(skb))  
  38.         goto drop;  
  39.     /*根据目的地类型做一些统计*/  
  40.     rt = skb_rtable(skb);  
  41.     if (rt->rt_type == RTN_MULTICAST) {  
  42.         IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INMCAST,  
  43.                 skb->len);  
  44.     } else if (rt->rt_type == RTN_BROADCAST)  
  45.         IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INBCAST,  
  46.                 skb->len);  
  47.     /"where to go 见下面"/  
  48.   
  49.     return dst_input(skb);  
  50.   
  51. drop:  
  52.     kfree_skb(skb);  
  53.     return NET_RX_DROP;  
  54. }  

 

 

这个决定L3包走向的函数指针在那里设置的呢,跟着我看一下吧

接着上一篇讲过的inet_init()->ip_init()->ip_rt_init()

-->

rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL);

<route.c __rtnl_register登记 >

-->

 

 

C代码  收藏代码
  1. int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,  
  2.                u8 tos, struct net_device *dev, bool noref)  
  3. {  
  4.     //...  
  5.             if (our ) {  
  6.                 int res = ip_route_input_mc(skb, daddr, saddr,  
  7.                                 tos, dev, our);  
  8.     //...  
  9.           
  10.             }  
  11.     //...  
  12.       
  13.     }  
  14. //...  
  15.   
  16.     res = ip_route_input_slow(skb, daddr, saddr, tos, dev);  
  17. }  
 

inet_rtm_getroute()->ip_route_input()->ip_route_input_common()-

 

A:ip_route_input_slow()

->ip_mkroute_input()->__mkroute_input()

"ip_forward;"

B<our>: ip_route_input_mc()

B1 "ip_local_deliver"

B2 "init_net.loopback_dev";

这是几个likely的不考虑异常分支,别的就先不介绍了

 

 

 

C代码  收藏代码
  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.   
  7.     if (skb_warn_if_lro(skb))  
  8.         goto drop;  
  9.   
  10.     if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))  
  11.         goto drop;  
  12.     /*Router Alert option 的处理,后面会分析 ip_call_ra_chain()函数*/  
  13.     if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))  
  14.         return NET_RX_SUCCESS;  
  15.     /*pkt_type在L2层处理的时候有无设置PACKET_HOST*/  
  16.     if (skb->pkt_type != PACKET_HOST)  
  17.         goto drop;  
  18.     /*什么都没做 直接让pass了*/  
  19.     skb_forward_csum(skb);  
  20.   
  21.     /*rfc 规定防止路由循环等等用的*/  
  22.     if (ip_hdr(skb)->ttl <= 1)  
  23.         goto too_many_hops;  
  24.   
  25.     /*VPN IPSec交给xfrm 框架处理转发*/  
  26.     if (!xfrm4_route_forward(skb))  
  27.         goto drop;  
  28.       
  29.     rt = skb_rtable(skb);  
  30.     /*如果IP包选项指明了要用自己提供的路由来走<Strict Source Routing >,而又不能满*足就失败*/  
  31.     if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)  
  32.         goto sr_failed;  
  33.     /*如果包长度大于了目的地的MTU 却禁止分包 就发送一个ICMP<这块参考 TCP/IP详解卷一 9章>*/  
  34.     if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&  
  35.              (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {  
  36.         IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);  
  37.         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,  
  38.               htonl(dst_mtu(&rt->dst)));  
  39.         goto drop;  
  40.     }  
  41.   
  42.     /* We are about to mangle packet. Copy it! 这个之前解释过了 */  
  43.     if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len))  
  44.         goto drop;  
  45.     iph = ip_hdr(skb);  
  46.   
  47.     /* Decrease ttl after skb cow done  协议要求*/  
  48.     ip_decrease_ttl(iph);  
  49.   
  50.     /* 
  51.      *如果包允许走别的路由而且他也表示希望走一个更好的,就重新计算路由,当然也会 * 引起一个ICMP ,这个函数后面分析     */  
  52.     if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb))  
  53.         ip_rt_send_redirect(skb);  
  54.       
  55.     /*根据 IP包头部的TOS 设置包优先级 给后面的 Traffic Control 用<ps: 路由器设计很重视这个选项>*/  
  56.     skb->priority = rt_tos2priority(iph->tos);  
  57.     /*之前分析过,经过NetFilter后调用ip_forward_finish*/  
  58.     return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev,  
  59.                rt->dst.dev, ip_forward_finish);  
  60.   
  61. sr_failed:  
  62.     /* 
  63.      *  Strict routing permits no gatewaying 协议规定的参考 TCP/IP-I 1 
  64.      */  
  65.      icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);  
  66.      goto drop;  
  67.   
  68. too_many_hops:  
  69.     /* Tell the sender its packet died... */  
  70.     IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_INHDRERRORS);  
  71.     icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);  
  72. drop:  
  73.     kfree_skb(skb);  
  74.     return NET_RX_DROP;  
  75. }  

 好吧 ,下面就是

 

 

 

C代码  收藏代码
  1. static int ip_forward_finish(struct sk_buff *skb)  
  2. {  
  3.     struct ip_options * opt = &(IPCB(skb)->opt);  
  4.   
  5.     IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);  
  6.     /* ip_forward里面已经处理了2个IP  options <Router Alert 和Strict Source Routing>,* 下面就是把剩下的处理完,由于几乎很少会用到IP-O <看看这里的unlikely也知道概率了吧* >所以就不分析了*/  
  7.     if (unlikely(opt->optlen))  
  8.         ip_forward_options(skb);  
  9.     /*最终归属,根据 消息包类型去调用相应的函数指针 ip_mc_output ..ip_finish_output */  
  10.     return dst_output(skb);  
  11. }  

 

 

 

=========================

补充上面说的 ip_call_ra_chian

 

 写道
struct ip_ra_chain {
struct ip_ra_chain __rcu *next;
struct sock *sk;
union {
void (*destructor)(struct sock *);
struct sock *saved_sk;
};
struct rcu_head rcu;
};

 int ip_call_ra_chain(struct sk_buff *skb)

C代码  收藏代码
  1. {  
  2.     struct ip_ra_chain *ra;  
  3.     u8 protocol = ip_hdr(skb)->protocol;  
  4.     struct sock *last = NULL;  
  5.     struct net_device *dev = skb->dev;  
  6.     /*这里遍历了整个raw sock 链表 */  
  7.     for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) {  
  8.         struct sock *sk = ra->sk;  
  9.   
  10.         /* If socket is bound to an interface, only report 
  11.          * the packet if it came  from that interface. 
  12.          */  
  13.     /*包头端口号和该raw sock 的端口匹配 设备接口序号也匹配*/  
  14.         if (sk && inet_sk(sk)->inet_num == protocol &&  
  15.             (!sk->sk_bound_dev_if ||  
  16.              sk->sk_bound_dev_if == dev->ifindex) &&  
  17.             net_eq(sock_net(sk), dev_net(dev))) {  
  18.     /*如果分段过 就去重组整个IP包 ip_fragment.c*/  
  19.             if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {  
  20.                 if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN))  
  21.                     return 1;  
  22.             }  
  23.             if (last) {  
  24.     /*关键就是这里,把包复制一遍然后传给上层 
  25.     *放入该sock的sk_receive_queue*/  
  26.                 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);  
  27.                 if (skb2)  
  28.                     raw_rcv(last, skb2);  
  29.             }  
  30.     /*下一个raw sock */  
  31.             last = sk;  
  32.         }  
  33.     }  
  34.   
  35.     if (last) {  
  36.         raw_rcv(last, skb);  
  37.         return 1;  
  38.     }  
原创粉丝点击