linux網路通訊協定棧分析筆記10-arp鄰居子系統3

來源:互聯網
上載者:User
還是回到neigh_resolve_output()int neigh_resolve_output(struct sk_buff *skb)

{
     struct dst_entry *dst = skb_dst(skb);
     struct neighbour *neigh;
     int rc = 0;

     if (!dst || !(neigh = dst->neighbour))        異常退出
          goto discard;

     __skb_pull(skb, skb_network_offset(skb));

     if (!neigh_event_send(neigh, skb)) {           判斷鄰居項是否有可用狀態,如果可用,則把資料包發送出去
           int err;
          struct net_device *dev = neigh->dev;
          if (dev->header_ops->cache && !dst->hh) {
               write_lock_bh(&neigh->lock);
               if (!dst->hh)
                    neigh_hh_init(neigh, dst, dst->ops->protocol);
               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                               neigh->ha, NULL, skb->len);
               write_unlock_bh(&neigh->lock);
          } else {
               read_lock_bh(&neigh->lock);
               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                               neigh->ha, NULL, skb->len);
               read_unlock_bh(&neigh->lock);
          }
          if (err >= 0)
               rc = neigh->ops->queue_xmit(skb);
          else
               goto out_kfree_skb;
     }
out:
     return rc;
discard:
     NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
                dst, dst ? dst->neighbour : NULL);
out_kfree_skb:
     rc = -EINVAL;
     kfree_skb(skb);
     goto out;
}

我們看鄰居項可用的情況下的發送過程:struct net_device *dev = neigh->dev;
          if (dev->header_ops->cache && !dst->hh) {      如果hh為空白   鄰居項的快取
               write_lock_bh(&neigh->lock);
               if (!dst->hh)
                    neigh_hh_init(neigh, dst, dst->ops->protocol);                進行hh的初始化
               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                               neigh->ha, NULL, skb->len);             根據HH的資訊構造二層頭
               write_unlock_bh(&neigh->lock);
          } else {                                                      hh不為空白時,直接根據HH的資訊構造二層頭
               read_lock_bh(&neigh->lock);
               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                               neigh->ha, NULL, skb->len);
               read_unlock_bh(&neigh->lock);
          }
          if (err >= 0)                                            加頭成功直接輸出
               rc = neigh->ops->queue_xmit(skb);         
          else
               goto out_kfree_skb;static const struct neigh_ops arp_hh_ops = {
     .family =          AF_INET,
     .solicit =          arp_solicit,
     .error_report =          arp_error_report,
     .output =          neigh_resolve_output,
     .connected_output =     neigh_resolve_output,
     .hh_output =          dev_queue_xmit,
     .queue_xmit =          dev_queue_xmit,
};static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
                 __be16 protocol)
{
     struct hh_cache     *hh;
     struct net_device *dev = dst->dev;

     for (hh = n->hh; hh; hh = hh->hh_next)             從路由的協議下手找
          if (hh->hh_type == protocol)
               break;

     if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {  找不到則申請
          seqlock_init(&hh->hh_lock);
          hh->hh_type = protocol;                     協議類型賦值
          atomic_set(&hh->hh_refcnt, 0);
          hh->hh_next = NULL;

          if (dev->header_ops->cache(n, hh)) {             該函數為eth_header_cache
               kfree(hh);
               hh = NULL;
          } else {
               atomic_inc(&hh->hh_refcnt);
               hh->hh_next = n->hh;
               n->hh         = hh;
               if (n->nud_state & NUD_CONNECTED)
                    hh->hh_output = n->ops->hh_output;
               else
                    hh->hh_output = n->ops->output;        
根據鄰居項的狀態選擇輸出函數
          }
     }
     if (hh)     {
          atomic_inc(&hh->hh_refcnt);
          dst->hh = hh;                       hh賦值
     }
}

int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
{
     __be16 type = hh->hh_type;
     struct ethhdr *eth;
     const struct net_device *dev = neigh->dev;

     eth = (struct ethhdr *)
         (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));

     if (type == htons(ETH_P_802_3))
          return -1;

     eth->h_proto = type;
     memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);           填充二層地址源 目的     memcpy(eth->h_dest, neigh->ha, ETH_ALEN);
     hh->hh_len = ETH_HLEN;                          
     return 0;
}

hh_cache中儲存的是鏈路頭的一些相關資訊,可以加快資料包的傳輸(因為有些情況下不用查看路由表,直接到此緩衝區查看).最後再來一張鄰居子系統的主要資料結構組織圖 from ULKI另附:這篇文章對arp狀態轉移分析得很透徹
http://blog.csdn.net/wearenoth/article/details/7794852  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.