天天看点

linux网络协议栈分析笔记10-arp邻居子系统3

还是回到 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