閱讀824 返回首頁    go 阿裏雲 go 技術社區[雲棲]


網絡子係統12_鄰居子係統垃圾回收

//	鄰居子係統垃圾回收機製:
//		1.異步回收機製:通過定時器,定期檢測鄰居緩存使用的內存閾值
//		2.同步回收機製:無法分配新neighbour實例時,同步回收內存。

//	同步,異步回收機製的區別:
//		1.同步回收比異步回收更加嚴格:
//			1.1 回收的數量:同步回收遍曆每一個bucket;
//				異步回收接著上次清理的bucket開始,隻清理一個bucket
//			1.2 回收的條件:同步回收視沒有被引用,非靜態配置的鄰居項均視為可回收項;
//				異步回收見下3.1
//		2.回收時機不同:
//			2.1 同步回收在分配新鄰居項失敗時,進行;異步回收定期進行
//		3.任務不同:
//			3.1異步回收機製負責隨機化neigh_parms->reachable_time


//	異步回收機製:
//		1.每300HZ隨機化鄰居協議參數的reachable_time
//		2.使用tbl->hash_chain_gc記錄下次gc清理的bucket
//		3.遍曆需要清理的bucket
//			3.1 選擇合適的清理對象:
//				3.1.1 非用戶配置的永久鄰居項,沒有定時器在運行的鄰居項
//				3.1.2 沒有被其他子係統引用
//				3.1.3 solicitation請求失敗,或者在一段時間內沒有被使用過
//			3.2 標記鄰居項為dead,釋放鄰居項
//		4.更新下次gc的到期時間
1.1 static void neigh_periodic_timer(unsigned long arg)
{
	struct neigh_table *tbl = (struct neigh_table *)arg;
	struct neighbour *n, **np;
	unsigned long expire, now = jiffies;
	//在協議鎖的保護下清理
	write_lock(&tbl->lock);

	//每300HZ隨機化鄰居參數的reachable_time
	if (time_after(now, tbl->last_rand + 300 * HZ)) {
		struct neigh_parms *p;
		tbl->last_rand = now;//上次更新隨機範圍的時間戳
		for (p = &tbl->parms; p; p = p->next)//與鄰居協議相關的調整參數保存在tbl->parms鏈表中
			p->reachable_time =
				neigh_rand_reach_time(p->base_reachable_time);
	}
	//tbl->hash_chain_gc用於記錄當前gc運行的bucket鏈表頭
	np = &tbl->hash_buckets[tbl->hash_chain_gc];
	//更新下次gc運行的bucket鏈表頭號
	tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask);
	while ((n = *np) != NULL) {
		unsigned int state;

		write_lock(&n->lock);
		//當前neighbour的狀態
		state = n->nud_state;
		//永久配置,或者運行了定時器的鄰居項不是合適的清理對象
		if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
			write_unlock(&n->lock);
			goto next_elt;
		}

		//鄰居項上一次使用的時間在其上一次可達性確認之前
		if (time_before(n->used, n->confirmed))
			n->used = n->confirmed;//上一次使用時間為上一次確認時間

		if (atomic_read(&n->refcnt) == 1 &&//隻有hash表引用此鄰居項
		    (state == NUD_FAILED ||//該鄰居項solicitation請求失敗,鄰居項為不可達
		     time_after(now, n->used + n->parms->gc_staletime))) {//或者鄰居項已近一段時間沒有被使用過
			*np = n->next;
			n->dead = 1;//標記該鄰居項將被刪除,不在使用
			write_unlock(&n->lock);
			neigh_release(n);//遞減當前引用計數,釋放鄰居項
			continue;
		}
		//解鎖neighbour
		write_unlock(&n->lock);

next_elt:
		np = &n->next;
	}
	//計算下一次到期時間 expire = (base_reachable_time/2)/(bucket size)
	expire = tbl->parms.base_reachable_time >> 1;
	expire /= (tbl->hash_mask + 1);
	if (!expire)
		expire = 1;
	//更新gc到期時間
 	mod_timer(&tbl->gc_timer, now + expire);
	write_unlock(&tbl->lock);
}


//	同步回收機製:
//		1.遍曆每個bucket
//			1.1 如果鄰居項非靜態配置,並且沒有被其他子係統引用,釋放鄰居項
//		2.更新neigh_forced_gc時間戳
1.2 static int neigh_forced_gc(struct neigh_table *tbl)
{
	int shrunk = 0;
	int i;

	//在協議表鎖的保護下,清理
	write_lock_bh(&tbl->lock);
	//遍曆每一個bucket
	for (i = 0; i <= tbl->hash_mask; i++) {
		struct neighbour *n, **np;
		np = &tbl->hash_buckets[i];
		while ((n = *np) != NULL) {
			//獲取neighbour的鎖
			write_lock(&n->lock);
			//鄰居項沒有被其他子係統引用
			if (atomic_read(&n->refcnt) == 1 &&
			    !(n->nud_state & NUD_PERMANENT)) {//並且l2地址並非靜態配置
				*np	= n->next;
				n->dead = 1;//標記當前neighbour將被刪除,不在使用
				shrunk	= 1;
				write_unlock(&n->lock);
				neigh_release(n);
				continue;
			}
			write_unlock(&n->lock);
			np = &n->next;//下一個
		}
	}
	//更新neigh_forced_gc時間戳
	tbl->last_flush = jiffies;

	write_unlock_bh(&tbl->lock);

	return shrunk;//返回是否有neighbour被釋放
}

最後更新:2017-04-03 15:21:56

  上一篇:go 網絡子係統13_鄰居子係統狀態機
  下一篇:go 網絡子係統11_arp子係統初始化