• 【Linux4.1.12源码分析】邻居子系统实现分析


    http://blog.csdn.net/one_clouder/article/details/52889921


    邻居子系统实现了IP层发包不感知MAC,即由邻居子系统实现了MAC头封装。MAC头信息包括:源MAC、目的MAC、协议类型,其中协议类型由上层指定,例如IPV4等等,源MAC地址是出口设备MAC地址(在路由表中确定出口设备),目的MAC是由邻居子系统提供的,大致可以猜到,邻居子系统会主动发起arp请求获取到mac地址,实现MAC封包。IP层发包最后会调用ip_finish_output2函数,我们从该函数入手分析邻居子系统。

    ip_finish_output2函数

    1. static inline int ip_finish_output2(struct sock *sk, struct sk_buff *skb)  
    2. {  
    3.     struct dst_entry *dst = skb_dst(skb);  
    4.     struct rtable *rt = (struct rtable *)dst;  
    5.     struct net_device *dev = dst->dev;       //出口设备  
    6.     unsigned int hh_len = LL_RESERVED_SPACE(dev);  
    7.     struct neighbour *neigh;  
    8.     u32 nexthop;  
    9.   
    10.     if (rt->rt_type == RTN_MULTICAST) {  
    11.         IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);  
    12.     } else if (rt->rt_type == RTN_BROADCAST)  
    13.         IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len);  
    14.   
    15.     /* Be paranoid, rather than too clever. */  
    16.     if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {  
    17.         struct sk_buff *skb2;  
    18.   
    19.         skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));  
    20.         if (!skb2) {  
    21.             kfree_skb(skb);  
    22.             return -ENOMEM;  
    23.         }  
    24.         if (skb->sk)  
    25.             skb_set_owner_w(skb2, skb->sk);  
    26.         consume_skb(skb);  
    27.         skb = skb2;  
    28.     }  
    29.   
    30.     rcu_read_lock_bh();  
    31.     nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);<span style="white-space:pre">  </span>//目的IP地址  
    32.     neigh = __ipv4_neigh_lookup_noref(dev, nexthop);    //根据目的IP查找邻居项是否存在  
    33.     if (unlikely(!neigh))  
    34.         neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); //如果不存在,则创建neigh项  
    35.     if (!IS_ERR(neigh)) {  
    36.         int res = dst_neigh_output(dst, neigh, skb);    //调用邻居子系统封装MAC头,并且调用二层发包函数完成报文发送  
    37.   
    38.         rcu_read_unlock_bh();  
    39.         return res;  
    40.     }  
    41.     rcu_read_unlock_bh();  
    42.   
    43.     net_dbg_ratelimited("%s: No header cache and no neighbour! ",  
    44.                 __func__);  
    45.     kfree_skb(skb);  
    46.     return -EINVAL;  
    47. }  
    首先会根据出口设备和目的IP地址,查找是否已经存在邻居项,如果没有则创建邻居项,然后通过dst_neigh_output发包,本文分析假设没有邻居项。 先邻居项的查找函数:

    __ipv4_neigh_lookup_noref函数

    1. static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)  
    2. {  
    3.     return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);  //ipv4从arp_tbl中查找  
    4. }  
    ___neigh_lookup_noref函数
    1. static inline struct neighbour *___neigh_lookup_noref(  
    2.     struct neigh_table *tbl,  
    3.     bool (*key_eq)(const struct neighbour *n, const void *pkey),  
    4.     __u32 (*hash)(const void *pkey,  
    5.               const struct net_device *dev,  
    6.               __u32 *hash_rnd),  
    7.     const void *pkey,  
    8.     struct net_device *dev)  
    9. {  
    10.     struct neigh_hash_table *nht = rcu_dereference_bh(tbl->nht); //hash表,邻居数量大时加速  
    11.     struct neighbour *n;  
    12.     u32 hash_val;  
    13.   
    14.     hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);    //计算hash值  
    15.     for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);  
    16.          n != NULL;  
    17.          n = rcu_dereference_bh(n->next)) {  
    18.         if (n->dev == dev && key_eq(n, pkey))    //dev相同并且pkey相同,这里pkey是IPV4地址  
    19.             return n;  
    20.     }  
    21.   
    22.     return NULL;  
    23. }  
    邻居表项查找比较简单,就是在hash表中查找匹配设备和目的IP地址的邻居表项,该函数支持IPV6, 可扩展性通过参数实现,接下来看下创建邻居表项的实现:

    __neigh_create函数

    1. struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,  
    2.                  struct net_device *dev, bool want_ref)  
    3. {  
    4.     u32 hash_val;  
    5.     int key_len = tbl->key_len;  
    6.     int error;  
    7.     struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);<span style="white-space:pre">      </span>//创建邻居表项对象  
    8.     struct neigh_hash_table *nht;  
    9.   
    10.     if (!n) {  
    11.         rc = ERR_PTR(-ENOBUFS);  
    12.         goto out;  
    13.     }  
    14.   
    15.     memcpy(n->primary_key, pkey, key_len);  
    16.     n->dev = dev;  
    17.     dev_hold(dev);  
    18.   
    19.     /* Protocol specific setup. */  
    20.     if (tbl->constructor &&  (error = tbl->constructor(n)) < 0) {  //IPV4实际调用arp_constructor函数,设置output函数  
    21.         rc = ERR_PTR(error);  
    22.         goto out_neigh_release;  
    23.     }  
    24.   
    25.     if (dev->netdev_ops->ndo_neigh_construct) {   //一般设备不设置该变量  
    26.         error = dev->netdev_ops->ndo_neigh_construct(n);  
    27.         if (error < 0) {  
    28.             rc = ERR_PTR(error);  
    29.             goto out_neigh_release;  
    30.         }  
    31.     }  
    32.   
    33.     /* Device specific setup. */  
    34.     if (n->parms->neigh_setup &&  
    35.         (error = n->parms->neigh_setup(n)) < 0) {  //IPV4未定义该函数  
    36.         rc = ERR_PTR(error);  
    37.         goto out_neigh_release;  
    38.     }  
    39.   
    40.     n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);  
    41.   
    42.     write_lock_bh(&tbl->lock);  
    43.     nht = rcu_dereference_protected(tbl->nht,  
    44.                     lockdep_is_held(&tbl->lock));  
    45.   
    46.     if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))  
    47.         nht = neigh_hash_grow(tbl, nht->hash_shift + 1);  
    48.   
    49.     hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);    //计算hash值,计算方式由邻居表定义  
    50.   
    51.     if (n->parms->dead) {  
    52.         rc = ERR_PTR(-EINVAL);  
    53.         goto out_tbl_unlock;  
    54.     }  
    55.   
    56.     for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val], //找到有相同hash值得neighbour链表  
    57.                         lockdep_is_held(&tbl->lock));  
    58.          n1 != NULL;  
    59.          n1 = rcu_dereference_protected(n1->next,  
    60.             lockdep_is_held(&tbl->lock))) {  
    61.         if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {  
    62.             if (want_ref)  
    63.                 neigh_hold(n1);  
    64.             rc = n1;  
    65.             goto out_tbl_unlock;  
    66.         }  
    67.     }  
    68.   
    69.     n->dead = 0;  
    70.     if (want_ref)  
    71.         neigh_hold(n);  
    72.     rcu_assign_pointer(n->next,  
    73.                rcu_dereference_protected(nht->hash_buckets[hash_val],  
    74.                              lockdep_is_held(&tbl->lock)));  //插入到链表中  
    75.     rcu_assign_pointer(nht->hash_buckets[hash_val], n);  
    76.     write_unlock_bh(&tbl->lock);  
    77.     neigh_dbg(2, "neigh %p is created ", n);  
    78.     rc = n;  
    79. out:  
    80.     return rc;  
    81. out_tbl_unlock:  
    82.     write_unlock_bh(&tbl->lock);  
    83. out_neigh_release:  
    84.     neigh_release(n);  
    85.     goto out;  
    86. }  
    neigh_alloc函数
    1. static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)  
    2. {  
    3.     struct neighbour *n = NULL;  
    4.     unsigned long now = jiffies;  
    5.     int entries;  
    6.   
    7.     entries = atomic_inc_return(&tbl->entries) - 1;  
    8.     if (entries >= tbl->gc_thresh3 ||  
    9.         (entries >= tbl->gc_thresh2 &&  
    10.          time_after(now, tbl->last_flush + 5 * HZ))) {  
    11.         if (!neigh_forced_gc(tbl) &&  
    12.             entries >= tbl->gc_thresh3)  
    13.             goto out_entries;  
    14.     }  
    15.   
    16.     n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);  
    17.     if (!n)  
    18.         goto out_entries;  
    19.   
    20.     __skb_queue_head_init(&n->arp_queue);    //初始化arp_queue队列  
    21.     rwlock_init(&n->lock);  
    22.     seqlock_init(&n->ha_lock);  
    23.     n->updated     = n->used = now;  
    24.     n->nud_state   = NUD_NONE;       //状态为不可用  
    25.     n->output      = neigh_blackhole;    //直接丢弃报文  
    26.     seqlock_init(&n->hh.hh_lock);  
    27.     n->parms   = neigh_parms_clone(&tbl->parms);  //拷贝neigh_table中的parms  
    28.     setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);   //注册定时器  
    29.   
    30.     NEIGH_CACHE_STAT_INC(tbl, allocs);  
    31.     n->tbl         = tbl;  
    32.     atomic_set(&n->refcnt, 1);  
    33.     n->dead        = 1;  
    34. out:  
    35.     return n;  
    36.   
    37. out_entries:  
    38.     atomic_dec(&tbl->entries);  
    39.     goto out;  
    40. }  
    arp_constructor函数
    1. static int arp_constructor(struct neighbour *neigh)  
    2. {  
    3.     __be32 addr = *(__be32 *)neigh->primary_key;  
    4.     struct net_device *dev = neigh->dev;  
    5.     struct in_device *in_dev;  
    6.     struct neigh_parms *parms;  
    7.   
    8.     rcu_read_lock();  
    9.     in_dev = __in_dev_get_rcu(dev);     //通过net_device得到in_device  
    10.     if (!in_dev) {  
    11.         rcu_read_unlock();  
    12.         return -EINVAL;  
    13.     }  
    14.   
    15.     neigh->type = inet_addr_type(dev_net(dev), addr);    //设置地址类型  
    16.   
    17.     parms = in_dev->arp_parms;  
    18.     __neigh_parms_put(neigh->parms);  
    19.     neigh->parms = neigh_parms_clone(parms);  
    20.     rcu_read_unlock();  
    21.   
    22.     if (!dev->header_ops) {      //基本上的网卡都会设置该值  
    23.         neigh->nud_state = NUD_NOARP;  
    24.         neigh->ops = &arp_direct_ops;  
    25.         neigh->output = neigh_direct_output;  
    26.     } else {  
    27.         /* Good devices (checked by reading texts, but only Ethernet is 
    28.            tested) 
    29.  
    30.            ARPHRD_ETHER: (ethernet, apfddi) 
    31.            ARPHRD_FDDI: (fddi) 
    32.            ARPHRD_IEEE802: (tr) 
    33.            ARPHRD_METRICOM: (strip) 
    34.            ARPHRD_ARCNET: 
    35.            etc. etc. etc. 
    36.  
    37.            ARPHRD_IPDDP will also work, if author repairs it. 
    38.            I did not it, because this driver does not work even 
    39.            in old paradigm. 
    40.          */  
    41.   
    42.         if (neigh->type == RTN_MULTICAST) {      //组播地址不需要arp  
    43.             neigh->nud_state = NUD_NOARP;  
    44.             arp_mc_map(addr, neigh->ha, dev, 1);  
    45.         } else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) {    //设备明确不需要arp或本地回环设备,不需要arp  
    46.             neigh->nud_state = NUD_NOARP;  
    47.             memcpy(neigh->ha, dev->dev_addr, dev->addr_len);  
    48.         } else if (neigh->type == RTN_BROADCAST ||  
    49.                (dev->flags & IFF_POINTOPOINT)) { //广播或点对点,也不需要arp  
    50.             neigh->nud_state = NUD_NOARP;  
    51.             memcpy(neigh->ha, dev->broadcast, dev->addr_len);  
    52.         }  
    53.   
    54.         if (dev->header_ops->cache)       //eth_header_ops包含cache  
    55.             neigh->ops = &arp_hh_ops;  
    56.         else  
    57.             neigh->ops = &arp_generic_ops;  
    58.   
    59.         if (neigh->nud_state & NUD_VALID)  
    60.             neigh->output = neigh->ops->connected_output;  
    61.         else  
    62.             neigh->output = neigh->ops->output;    //初始阶段为该值,即arp_hh_ops的neigh_resolve_output函数  
    63.     }  
    64.     return 0;  
    65. }  
    邻居表项创建后,output函数为neigh_resolve_output,此时邻居子系统还不具备发送IP报文的能力,因为目的MAC地址还未获取,我们来看下dst_neigh_output函数实现:

    dst_neigh_output函数

    1. static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,  
    2.                    struct sk_buff *skb)  
    3. {  
    4.     const struct hh_cache *hh;  
    5.   
    6.     if (dst->pending_confirm) {  
    7.         unsigned long now = jiffies;  
    8.   
    9.         dst->pending_confirm = 0;  
    10.         /* avoid dirtying neighbour */  
    11.         if (n->confirmed != now)  
    12.             n->confirmed = now;  
    13.     }  
    14.   
    15.     hh = &n->hh;  
    16.     if ((n->nud_state & NUD_CONNECTED) && hh->hh_len) //如果neighbour已连接且hh已设置  
    17.         return neigh_hh_output(hh, skb);  
    18.     else  
    19.         return n->output(n, skb);    //初始阶段调用此函数,此时为neigh_resolve_output函数  
    20. }  
    neigh_resolve_output函数
    1. int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)  
    2. {  
    3.     int rc = 0;  
    4.   
    5.     if (!neigh_event_send(neigh, skb)) {        //发送arp请求,第一次返回true  
    6.         int err;  
    7.         struct net_device *dev = neigh->dev;  
    8.         unsigned int seq;  
    9.   
    10.         if (dev->header_ops->cache && !neigh->hh.hh_len)  
    11.             neigh_hh_init(neigh);       //初始化MAC缓存值,目的是加速  
    12.   
    13.         do {  
    14.             __skb_pull(skb, skb_network_offset(skb));   //常见情况,skb指向network header  
    15.             seq = read_seqbegin(&neigh->ha_lock);  
    16.             err = dev_hard_header(skb, dev, ntohs(skb->protocol),  //封装MAC头  
    17.                           neigh->ha, NULL, skb->len);  
    18.         } while (read_seqretry(&neigh->ha_lock, seq));  
    19.   
    20.         if (err >= 0)  
    21.             rc = dev_queue_xmit(skb);   //二层发送报文  
    22.         else  
    23.             goto out_kfree_skb;  
    24.     }  
    25. out:  
    26.     return rc;  
    27. out_kfree_skb:  
    28.     rc = -EINVAL;  
    29.     kfree_skb(skb);  
    30.     goto out;  
    31. }  
    neigh_event_send函数
    1. static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)  
    2. {  
    3.     unsigned long now = jiffies;  
    4.       
    5.     if (neigh->used != now)  
    6.         neigh->used = now;  
    7.     if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))  
    8.         return __neigh_event_send(neigh, skb);  //发送arp请求  
    9.     return 0;  
    10. }  
    __neigh_event_send函数
    1. int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)  
    2. {  
    3.     int rc;  
    4.     bool immediate_probe = false;  
    5.   
    6.     write_lock_bh(&neigh->lock);  
    7.   
    8.     rc = 0;  
    9.     if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))  
    10.         goto out_unlock_bh;  
    11.     if (neigh->dead)  
    12.         goto out_dead;  
    13.   
    14.     if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {    //初始阶段进入此分支  
    15.         if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +  
    16.             NEIGH_VAR(neigh->parms, APP_PROBES)) {  
    17.             unsigned long next, now = jiffies;  
    18.   
    19.             atomic_set(&neigh->probes,  
    20.                    NEIGH_VAR(neigh->parms, UCAST_PROBES));  
    21.             neigh->nud_state     = NUD_INCOMPLETE;       //设置表项状态为incomplete  
    22.             neigh->updated = now;  
    23.             next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),  
    24.                      HZ/2);  
    25.             neigh_add_timer(neigh, next);   //触发定时器,期望刷新表项状态和output函数,500毫秒后执行  
    26.             immediate_probe = true;  
    27.         } else {  
    28.             neigh->nud_state = NUD_FAILED;  
    29.             neigh->updated = jiffies;  
    30.             write_unlock_bh(&neigh->lock);  
    31.   
    32.             kfree_skb(skb);  
    33.             return 1;  
    34.         }  
    35.     } else if (neigh->nud_state & NUD_STALE) {  
    36.         neigh_dbg(2, "neigh %p is delayed ", neigh);  
    37.         neigh->nud_state = NUD_DELAY;  
    38.         neigh->updated = jiffies;  
    39.         neigh_add_timer(neigh, jiffies +  
    40.                 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));  
    41.     }  
    42.   
    43.     if (neigh->nud_state == NUD_INCOMPLETE) {  
    44.         if (skb) {  
    45.             while (neigh->arp_queue_len_bytes + skb->truesize >  
    46.                    NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {   //如果等待发送的报文数量超过设定值,丢弃报文  
    47.                 struct sk_buff *buff;  
    48.   
    49.                 buff = __skb_dequeue(&neigh->arp_queue);  
    50.                 if (!buff)  
    51.                     break;  
    52.                 neigh->arp_queue_len_bytes -= buff->truesize;  
    53.                 kfree_skb(buff);  
    54.                 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);  
    55.             }  
    56.             skb_dst_force(skb);  
    57.             __skb_queue_tail(&neigh->arp_queue, skb);    //报文放入arp_queue队列中  
    58.             neigh->arp_queue_len_bytes += skb->truesize;  
    59.         }  
    60.         rc = 1;  
    61.     }  
    62. out_unlock_bh:  
    63.     if (immediate_probe)        //初始阶段,邻居项设置状态设置为incomplete,同时设置该变量为true  
    64.         neigh_probe(neigh); //探测邻居表项  
    65.     else  
    66.         write_unlock(&neigh->lock);  
    67.     local_bh_enable();  
    68.     return rc;  
    69.   
    70. out_dead:  
    71.     if (neigh->nud_state & NUD_STALE)  
    72.         goto out_unlock_bh;  
    73.     write_unlock_bh(&neigh->lock);  
    74.     kfree_skb(skb);  
    75.     return 1;  
    76. }  
    neigh_probe函数
    1. static void neigh_probe(struct neighbour *neigh)  
    2.     __releases(neigh->lock)  
    3. {  
    4.     struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);  //取出报文  
    5.     /* keep skb alive even if arp_queue overflows */  
    6.     if (skb)  
    7.         skb = skb_copy(skb, GFP_ATOMIC);    //拷贝skb  
    8.     write_unlock(&neigh->lock);  
    9.     neigh->ops->solicit(neigh, skb);  //实际调用arp_solicit函数,该函数会发送arp请求  
    10.     atomic_inc(&neigh->probes);  
    11.     kfree_skb(skb);  
    12. }  
    从上述函数可以看到,报文并没有被发送出去,做了3个事情:1)发送了arp请求, 2)缓存了报文,3)启动定时器500毫秒后执行。 报文被丢弃了? 没有,其实报文是在neigh_update函数中被发送的,该函数的一个调用者是arp处理函数。 调用neigh_update函数后,neigh的output函数被改变,在这个之前,ouput函数仍然是neigh_resolve_output,如果是同一个目的IP,不会再次发送arp请求,仅仅把报文缓存起来,下面我们来看下neigh_update函数:

    neigh_update函数

    1. /* Generic update routine. 
    2.    -- lladdr is new lladdr or NULL, if it is not supplied. 
    3.    -- new    is new state. 
    4.    -- flags 
    5.     NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr, 
    6.                 if it is different. 
    7.     NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected" 
    8.                 lladdr instead of overriding it 
    9.                 if it is different. 
    10.                 It also allows to retain current state 
    11.                 if lladdr is unchanged. 
    12.     NEIGH_UPDATE_F_ADMIN    means that the change is administrative. 
    13.  
    14.     NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing 
    15.                 NTF_ROUTER flag. 
    16.     NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as 
    17.                 a router. 
    18.  
    19.    Caller MUST hold reference count on the entry. 
    20.  */  
    21.   
    22. int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,  
    23.          u32 flags)  
    24. {  
    25.     u8 old;  
    26.     int err;  
    27.     int notify = 0;  
    28.     struct net_device *dev;  
    29.     int update_isrouter = 0;  
    30.   
    31.     write_lock_bh(&neigh->lock);  
    32.   
    33.     dev    = neigh->dev;  
    34.     old    = neigh->nud_state;  
    35.     err    = -EPERM;  
    36.   
    37.     if (!(flags & NEIGH_UPDATE_F_ADMIN) &&  
    38.         (old & (NUD_NOARP | NUD_PERMANENT)))  
    39.         goto out;  
    40.     if (neigh->dead)  
    41.         goto out;  
    42.   
    43.     if (!(new & NUD_VALID)) {  
    44.         neigh_del_timer(neigh);  
    45.         if (old & NUD_CONNECTED)  
    46.             neigh_suspect(neigh);  
    47.         neigh->nud_state = new;  
    48.         err = 0;  
    49.         notify = old & NUD_VALID;  
    50.         if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&  
    51.             (new & NUD_FAILED)) {  
    52.             neigh_invalidate(neigh);  
    53.             notify = 1;  
    54.         }  
    55.         goto out;  
    56.     }  
    57.   
    58.     /* Compare new lladdr with cached one */  
    59.     if (!dev->addr_len) {  
    60.         /* First case: device needs no address. */  
    61.         lladdr = neigh->ha;  
    62.     } else if (lladdr) {  
    63.         /* The second case: if something is already cached 
    64.            and a new address is proposed: 
    65.            - compare new & old 
    66.            - if they are different, check override flag 
    67.          */  
    68.         if ((old & NUD_VALID) &&  
    69.             !memcmp(lladdr, neigh->ha, dev->addr_len))  
    70.             lladdr = neigh->ha;  
    71.     } else {  
    72.         /* No address is supplied; if we know something, 
    73.            use it, otherwise discard the request. 
    74.          */  
    75.         err = -EINVAL;  
    76.         if (!(old & NUD_VALID))  
    77.             goto out;  
    78.         lladdr = neigh->ha;  
    79.     }  
    80.   
    81.     if (new & NUD_CONNECTED)  
    82.         neigh->confirmed = jiffies;  
    83.     neigh->updated = jiffies;  
    84.   
    85.     /* If entry was valid and address is not changed, 
    86.        do not change entry state, if new one is STALE. 
    87.      */  
    88.     err = 0;  
    89.     update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;  
    90.     if (old & NUD_VALID) {  
    91.         if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {  
    92.             update_isrouter = 0;  
    93.             if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&  
    94.                 (old & NUD_CONNECTED)) {  
    95.                 lladdr = neigh->ha;  
    96.                 new = NUD_STALE;  
    97.             } else  
    98.                 goto out;  
    99.         } else {  
    100.             if (lladdr == neigh->ha && new == NUD_STALE &&  
    101.                 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||  
    102.                  (old & NUD_CONNECTED))  
    103.                 )  
    104.                 new = old;  
    105.         }  
    106.     }  
    107.   
    108.     if (new != old) {  
    109.         neigh_del_timer(neigh);  
    110.         if (new & NUD_IN_TIMER)  
    111.             neigh_add_timer(neigh, (jiffies +  
    112.                         ((new & NUD_REACHABLE) ?  
    113.                          neigh->parms->reachable_time :  
    114.                          0)));  
    115.         neigh->nud_state = new;  
    116.         notify = 1;  
    117.     }  
    118.   
    119.     if (lladdr != neigh->ha) {  
    120.         write_seqlock(&neigh->ha_lock);  
    121.         memcpy(&neigh->ha, lladdr, dev->addr_len);  
    122.         write_sequnlock(&neigh->ha_lock);  
    123.         neigh_update_hhs(neigh);  
    124.         if (!(new & NUD_CONNECTED))  
    125.             neigh->confirmed = jiffies -  
    126.                       (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);  
    127.         notify = 1;  
    128.     }  
    129.     if (new == old)  
    130.         goto out;  
    131.     if (new & NUD_CONNECTED)  
    132.         neigh_connect(neigh);   //修改output函数为neigh_connected_output  
    133.     else  
    134.         neigh_suspect(neigh);  
    135.     if (!(old & NUD_VALID)) {   //如果源状态不为valid,则发送缓存的skb  
    136.         struct sk_buff *skb;  
    137.   
    138.         /* Again: avoid dead loop if something went wrong */  
    139.   
    140.         while (neigh->nud_state & NUD_VALID &&  
    141.                (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {   //取出缓冲报文  
    142.             struct dst_entry *dst = skb_dst(skb);  
    143.             struct neighbour *n2, *n1 = neigh;  
    144.             write_unlock_bh(&neigh->lock);  
    145.   
    146.             rcu_read_lock();  
    147.   
    148.             /* Why not just use 'neigh' as-is?  The problem is that 
    149.              * things such as shaper, eql, and sch_teql can end up 
    150.              * using alternative, different, neigh objects to output 
    151.              * the packet in the output path.  So what we need to do 
    152.              * here is re-lookup the top-level neigh in the path so 
    153.              * we can reinject the packet there. 
    154.              */  
    155.             n2 = NULL;  
    156.             if (dst) {  
    157.                 n2 = dst_neigh_lookup_skb(dst, skb);  
    158.                 if (n2)  
    159.                     n1 = n2;  
    160.             }  
    161.             n1->output(n1, skb);     //调用neigh的output函数,此时已经改成connect函数  
    162.             if (n2)  
    163.                 neigh_release(n2);  
    164.             rcu_read_unlock();  
    165.   
    166.             write_lock_bh(&neigh->lock);  
    167.         }  
    168.         __skb_queue_purge(&neigh->arp_queue);    //清空缓存  
    169.         neigh->arp_queue_len_bytes = 0;  
    170.     }  
    171. out:  
    172.     if (update_isrouter) {  
    173.         neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?  
    174.             (neigh->flags | NTF_ROUTER) :  
    175.             (neigh->flags & ~NTF_ROUTER);  
    176.     }  
    177.     write_unlock_bh(&neigh->lock);  
    178.   
    179.     if (notify)  
    180.         neigh_update_notify(neigh);  
    181.   
    182.     return err;  
    183. }  
    至此,arp的整个大流程基本清晰了,有些细节还有待梳理,例如neigh_update中发包时,为什么需要重新查找neigh表项而不用当前的neigh等。
  • 相关阅读:
    git项目管理-合并请求
    记录一次git stash找回删除的存储
    chrome 下 position:fixed失效(react)
    css3 var变量
    rc-select下拉选择控件库推荐
    (转载)vue路径后面去除#号
    本地配置独立域名环境
    javascript判断pc还是手机端
    javascript复制到粘贴板的方案
    javascript轮播插件的使用(TouchSlide)
  • 原文地址:https://www.cnblogs.com/ztguang/p/12644606.html
Copyright © 2020-2023  润新知