Linux核心分析

來源:互聯網
上載者:User

核心版本:2.6.34

這篇是關於IP層協議接收報文時的處理,重點說明了路由表的尋找,以及IP分區重組。

ip_rcv 進入IP層報文接收函數

丟棄掉不是發往原生報文,skb->pkt_type在網卡接收報文處理乙太網路頭時會根據dst mac設定, 協議棧的書會講不是發往原生廣播報文會在二層被丟棄,實際上丟棄是發生在進入上層之初。

if (skb->pkt_type == PACKET_OTHERHOST)      goto drop;

在取IP前序時要注意可能帶有選項,因此報文長度應當以iph->ihl * 4為準。這裡就需要嘗試兩次, 第一次嘗試sizeof(struct iphdr),只是為了確保skb還可以容納標準的前序(即20位元組),然後可以ip_hdr(skb)得到前序;第二 次嘗試ihl * 4,這才是報文的真正長度,然後重新調用ip_hdr(skb)來得到前序。兩次嘗試pull後要重新調用ip_hdr()的原因是 pskb_may_pull()可能會調用__pskb_pull_tail()來改現現有的skb結構。

if (!pskb_may_pull(skb, sizeof(struct iphdr)))      goto inhdr_error;     iph = ip_hdr(skb);     ……     if (!pskb_may_pull(skb, iph->ihl*4))      goto inhdr_error;     iph = ip_hdr(skb);

擷取到IP前序後經過一些檢查,擷取到報文的總長度len = iph->tot_len,此時調用 pskb_trim_rcsum()去除多餘的位元組,即大於len的。

if (pskb_trim_rcsum(skb, len)) {      IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);      goto drop;     }

然後調用ip_rcv_finish()繼續IP層的處理,ip_rcv()可以看成是尋找路由前的IP層處理,接下來的ip_rcv_finish() 會尋找路由表,兩者間調用插入的netfilter(關於NetFilter,參考前篇 http://blog.csdn.net/qy532846454/article/details/6605592)。

return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish);

進入ip_rcv_finish函數

ip_rcv_finish()主要工作是完成路由表的查詢,決定報 文經過IP層處理後,是繼續向上傳遞,還是進行轉寄,還是丟棄。

剛開始沒有進行路由表查詢,所以還沒有相應的路由表項 :skb_dst(skb) == NULL。則在路由表中尋找ip_route_input(),關於核心的路由表,可以參見前篇 http://blog.csdn.net/qy532846454/article/details/6726171:

if (skb_dst(skb) == NULL) {      int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,            skb->dev);      if (unlikely(err)) {       if (err == -EHOSTUNREACH)        IP_INC_STATS_BH(dev_net(skb->dev),          IPSTATS_MIB_INADDRERRORS);       else if (err == -ENETUNREACH)        IP_INC_STATS_BH(dev_net(skb->dev),          IPSTATS_MIB_INNOROUTES);       goto drop;      }     }

通過路由表尋找,我們知道:

- 如果是丟棄的報文,則直接drop;

- 如果是不能接收或轉寄的報文,則 input = ip_error

- 如果是發往本機報文,則input = ip_local_deliver;

- 如果是廣播報文,則input = ip_local_deliver;

- 如果是組播報文,則input = ip_local_deliver;

- 如果是轉寄的報文,則input = ip_forward ;

在ip_rcv_finish()最後,會調用尋找到的路由項_skb_dst->input()繼續向上傳遞:

return dst_input (skb);

具體看下各種情況下的報文傳遞,如果是丟棄的報文,則報文被釋放,並從IP協議層返回,完成此次報文傳遞流 程。

drop:      kfree_skb(skb);      return NET_RX_DROP;

如果是不能處理的報文,則執行ip_error,根據error類型發送相應的ICMP錯誤判文。

static int ip_error(struct sk_buff *skb)     {      struct rtable *rt = skb_rtable(skb);      unsigned long now;      int code;               switch (rt->u.dst.error) {       case EINVAL:       default:        goto out;       case EHOSTUNREACH:        code = ICMP_HOST_UNREACH;        break;       case ENETUNREACH:        code = ICMP_NET_UNREACH;        IP_INC_STATS_BH(dev_net(rt->u.dst.dev),          IPSTATS_MIB_INNOROUTES);        break;       case EACCES:        code = ICMP_PKT_FILTERED;        break;      }               now = jiffies;      rt->u.dst.rate_tokens += now - rt->u.dst.rate_last;      if (rt->u.dst.rate_tokens > ip_rt_error_burst)       rt->u.dst.rate_tokens = ip_rt_error_burst;      rt->u.dst.rate_last = now;      if (rt->u.dst.rate_tokens >= ip_rt_error_cost) {       rt->u.dst.rate_tokens -= ip_rt_error_cost;       icmp_send(skb, ICMP_DEST_UNREACH, code, 0);      }              out: kfree_skb(skb);      return 0;     }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.