鄰居子系統
/*
* Neighbor Cache Entry States.
*/
#define NUD_INCOMPLETE 0x01 發包時建立條目
#define NUD_REACHABLE 0x02
#define NUD_STALE 0x04 收到ARP請求
#define NUD_DELAY 0x08
#define NUD_PROBE 0x10
#define NUD_FAILED 0x20
/* Dummy states */
#define NUD_NOARP 0x40
#define NUD_PERMANENT 0x80
#define NUD_NONE 0x00
net/ipv4/route.c
ipv4_neigh_lookup
查找路由緩存
->__ipv4_neigh_lookup
->arp_hashfn
->neigh_create(&arp_tbl, pkey, dev)
->neigh_alloc
->nud_state = NUD_NONE
->setup_timer(&n->timer, neigh_timer_handler
->tbl->constructor/arp_constructor
->dev->netdev_ops->ndo_neigh_construct
->n->parms->neigh_setup
->neigh_hash_grow
->tbl->hash
ip_finish_output2
發包
->dst_neigh_output
->nud_state & NUD_CONNECTED neigh_hh_output
->n->output/neigh_resolve_output
->neigh_event_send
->__neigh_event_send
__neigh_event_send
->NUD_CONNECTED | NUD_DELAY | NUD_PROBE: 傳回,直接使用鄰居發包
->NUD_NONE: mcast_probes + neigh->parms->app_probes轉NUD_INCOMPLETE,探測、否則轉FALIED,丢skb
->NUD_STALE: 切NUD_DELAY
->NUD_INCOMPLETE: __skb_queue_tail(&neigh->arp_queue,緩存封包
->neigh_probe
->neigh->ops->solicit/arp_solicit
->arp_send
arp_rcv
收到arp封包
->arp_process
1. 丢棄目的位址是多點傳播或loopback的arp資料
2. 對于源ip位址是0的arp請求,一般用于重複位址檢測,此時如果arp類型為request,且目的ip位址是本地位址,且可以進行arp應答時,則調用arp_send發送arp reply資料包
3. 對于arp類型為request的資料包,且能找到到目的位址tip的路由
1)如果路由緩存對應的ip位址類型為local,則調用neigh_event_ns,查找符合條件的鄰居項
->neigh_event_ns
->__neigh_lookup
->neigh_update(NUD_STALE, NEIGH_UPDATE_F_OVERRIDE)
a)如果找到符合條件的鄰居項,則調用arp_send發送對該arp request包的reply包,并傳回
b)直接傳回。
2)如果路由緩存對應的ip位址類型不是local,則進行arp proxy的處理,完成後直接傳回
4. 調用__neigh_lookup,查找arp_tbl的neighbour hash bucket,查找sip對應的鄰居項
對于非由arp請求的arp reply,且沒有相應的neighbour,則強制建立新的neighbour
5. 查找到符合條件的neighbour
1)對于發給給本機的arp reply封包,則将鄰居項設定為reach狀态
2)對于發給給本機的arp request封包,則将鄰居項狀态設定為stale狀态
3)調用neigh_update,更新neighbour的狀态
neigh_add
->neigh_lookup
->neigh_event_send
->neigh_update(NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE)
neigh_periodic_work
周期reachable_time,每300s重新随機生成
NUD_PERMANENT | NUD_IN_TIMER(NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)不處理,僅處理NUD_STALE|NUD_FAILED
->NUD_FAILED狀态,引用計數為,删除;NUD_STALE狀态gc_staletime時間未使用,删除
->neigh_cleanup_and_release
neigh_timer_handler
僅處理NUD_IN_TIMER(NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)狀态條目
->NUD_REACHABLE
neigh->confirmed: 最近收到來自對應鄰居項的封包時間;neigh->used: 最近使用該鄰居項的時間
->confirm未逾時,不更改狀态,修改逾時時間reachable_time
->confirm逾時,used未逾時,狀态轉NUD_DELAY,修改逾時時間delay_probe_time,停fast path
->confirm逾時、used逾時,狀态轉NUD_STALE,停fast path
->NUD_DELAY(減少ARP包的數目,期望在定時時間内會收到對方的确認封包)
->收到對方封包,狀态轉NUD_REACHABLE,開fast path
->逾時,未收到對方封包,狀态轉NUD_PROBE
->NUD_PROBE|NUD_INCOMPLETE:
->超過最大probe次數轉NUD_FAILED,從arp_queue移除skb
調整下次逾時時間
->NUD_INCOMPLETE | NUD_PROBE
->neigh_probe
struct neigh_table arp_tbl = {
.family = AF_INET,
.key_len = ,
.hash = arp_hash,
.constructor = arp_constructor,
.proxy_redo = parp_redo(arp_process),
.id = "arp_cache",
.parms = {
.tbl = &arp_tbl,
.base_reachable_time = * HZ,
.retrans_time = * HZ,
.gc_staletime = * HZ,
.reachable_time = * HZ,
.delay_probe_time = * HZ,
.queue_len_bytes = *,
.ucast_probes = ,
.mcast_probes = ,
.anycast_delay = * HZ,
.proxy_delay = ( * HZ) / ,
.proxy_qlen = ,
.locktime = * HZ,
},
.gc_interval = * HZ,
.gc_thresh1 = ,
.gc_thresh2 = ,
.gc_thresh3 = ,
};
net/ipv4/arp.c
arp_init
->neigh_table_init(&arp_tbl)
->neigh_table_init_no_netlink
->neigh_rand_reach_time
->neigh_hash_alloc
->neigh_periodic_work
->schedule_delayed_work(&tbl->gc_work
->neigh_proxy_process
->skb_queue_head_init_class(&tbl->proxy_queue