歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux協議棧之鄰居子系統(相關流程四)

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,並設置定時器。定時器對應的處理函數為:

Copyright © Linux教程網 All Rights Reserved