int neigh_resolve_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
struct neighbour *neigh;
int rc = 0;
// 有效性判斷
if (!dst || !(neigh = dst->neighbour))
goto discard;
__skb_pull(skb, skb->nh.raw - skb->data);
//判斷鄰居項是否有可用狀態,如果可用,則把數據包發送出去
if (!neigh_event_send(neigh, skb)) {
int err;
struct net_device *dev = neigh->dev;
if (dev->hard_header_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;
}
轉向neigh_event_send();
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
neigh->used = jiffies;
//在這裡剔除了NUD_STALE狀態,因為,在此狀態有發送信息的時候,會將它轉入延遲狀態,並設置定時器,這在__neigh_event_send()中可以看到
if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
return __neigh_event_send(neigh, skb);
return 0;
}
我們假設對應鄰居項是新建項,初始條件都不滿足,轉入__neigh_event_send()
int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
int rc;
unsigned long now;
write_lock_bh(&neigh->lock);
rc = 0;
//入口參數檢測
if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
goto out_unlock_bh;
now = jiffies;
//如果狀態不為NUD_STALE和NUD_INCOMPLETE
if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
//設狀態為NUD_INCOMPLETE,且設置定時器
atomic_set(&neigh->probes, neigh->parms->ucast_probes);
neigh->nud_state = NUD_INCOMPLETE;
neigh_hold(neigh);
neigh->timer.expires = now + 1;
add_timer(&neigh->timer);
} else {
//如果延時參數末設置,設此鄰居不可用
neigh->nud_state = NUD_FAILED;
write_unlock_bh(&neigh->lock);
if (skb)
kfree_skb(skb);
return 1;
}
} else if (neigh->nud_state & NUD_STALE) {
//若狀態為NUD_STALE,則將狀態改為NUD_DELAY,並設置定時器
//返回零,在neigh_resolve_output中,將包送出
NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
neigh_hold(neigh);
neigh->nud_state = NUD_DELAY;
neigh->timer.expires = jiffies + neigh->parms->delay_probe_time;
add_timer(&neigh->timer);
}
if (neigh->nud_state == NUD_INCOMPLETE) {
//將包加至neigh, arp_queue, skb隊尾
if (skb) {
//如果隊列超長,則將arp_queue最前的一個數據包丟棄
if (skb_queue_len(&neigh->arp_queue) >=
neigh->parms->queue_len) {
struct sk_buff *buff;
buff = neigh->arp_queue.next;
__skb_unlink(buff, &neigh->arp_queue);
kfree_skb(buff);
}
//將包加至隊尾
__skb_queue_tail(&neigh->arp_queue, skb);
}
rc = 1;
}
out_unlock_bh:
write_unlock_bh(&neigh->lock);
return rc;
}
上述流程,主要判斷dst對應的鄰居項狀態,若狀態可用,則直接將包發出。若不可用,將狀態設為NUD_INCOMPLETE,並設置定時器。定時器對應的處理函數為: