⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 neighbour.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* neighbour.c * linqianghe@163.com * 2006-09-26 */#include "neighbour.h"#include "log.h"#include <linux/proc_fs.h>#include <linux/random.h>#include <net/dst.h>#define PNEIGH_HASHMASK		0xFstruct neigh_table myarp_tbl;static DEFINE_RWLOCK( myneigh_tbl_lock );static struct neigh_table *myneigh_tables;#ifdef CONFIG_PROC_FSstatic struct neighbour *myneigh_get_first(struct seq_file *seq){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	struct neighbour *n = NULL;	int bucket = state->bucket;	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;	for (bucket = 0; bucket <= tbl->hash_mask; bucket++) {		n = tbl->hash_buckets[bucket];		while (n) {			if (state->neigh_sub_iter) {				loff_t fakep = 0;				void *v;				v = state->neigh_sub_iter(state, n, &fakep);				if (!v)					goto next;			}			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))				break;			if (n->nud_state & ~NUD_NOARP)				break;		next:			n = n->next;		}		if (n) break;	}	state->bucket = bucket;	return n;}static struct neighbour *myneigh_get_next(struct seq_file *seq,					struct neighbour *n,					loff_t *pos){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	if (state->neigh_sub_iter) {		void *v = state->neigh_sub_iter(state, n, pos);		if (v) return n;	}	n = n->next;	while (1) {		while (n) {			if (state->neigh_sub_iter) {				void *v = state->neigh_sub_iter(state, n, pos);				if (v) return n;				goto next;			}			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))				break;			if (n->nud_state & ~NUD_NOARP)				break;next:			n = n->next;		}		if (n) break;		if (++state->bucket > tbl->hash_mask)			break;		n = tbl->hash_buckets[state->bucket];	}	if (n && pos)		--(*pos);	return n;}static struct neighbour *myneigh_get_idx(struct seq_file *seq, loff_t *pos){	struct neighbour *n = myneigh_get_first(seq);	if (n) {		while (*pos) {			n = myneigh_get_next(seq, n, pos);			if (!n) break;		}	}	return *pos ? NULL : n;}static struct pneigh_entry *mypneigh_get_first(struct seq_file *seq){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	struct pneigh_entry *pn = NULL;	int bucket = state->bucket;	state->flags |= NEIGH_SEQ_IS_PNEIGH;	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {		pn = tbl->phash_buckets[bucket];		if (pn) break;	}	state->bucket = bucket;	return pn;}static struct pneigh_entry *mypneigh_get_next( struct seq_file *seq,					    struct pneigh_entry *pn, loff_t *pos ){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	pn = pn->next;	while (!pn) {		if (++state->bucket > PNEIGH_HASHMASK)			break;		pn = tbl->phash_buckets[state->bucket];		if (pn) break;	}	if (pn && pos) --(*pos);	return pn;}static struct pneigh_entry *mypneigh_get_idx(struct seq_file *seq, loff_t *pos){	struct pneigh_entry *pn = mypneigh_get_first(seq);	if (pn) {		while (*pos) {			pn = mypneigh_get_next(seq, pn, pos);			if (!pn) break;		}	}	return *pos ? NULL : pn;}static void *myneigh_get_idx_any(struct seq_file *seq, loff_t *pos){	struct neigh_seq_state *state = seq->private;	void *rc;	rc = myneigh_get_idx(seq, pos);	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))		rc = mypneigh_get_idx(seq, pos);	return rc;}void *myneigh_seq_start(struct seq_file *seq, loff_t *pos, 				struct neigh_table *tbl, unsigned int neigh_seq_flags){	struct neigh_seq_state *state = seq->private;	loff_t pos_minus_one;	state->tbl = tbl;	state->bucket = 0;	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);	read_lock_bh(&tbl->lock);	pos_minus_one = *pos - 1;	return *pos ? myneigh_get_idx_any(seq, &pos_minus_one) : SEQ_START_TOKEN;}EXPORT_SYMBOL_GPL( myneigh_seq_start );void *myneigh_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct neigh_seq_state *state;	void *rc;	if (v == SEQ_START_TOKEN) {		rc = myneigh_get_idx(seq, pos);		goto out;	}	state = seq->private;	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {		rc = myneigh_get_next(seq, v, NULL);		if (rc)			goto out;		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))			rc = mypneigh_get_first(seq);	} else {		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);		rc = mypneigh_get_next(seq, v, NULL);	}out:	++(*pos);	return rc;}EXPORT_SYMBOL_GPL( myneigh_seq_next );void myneigh_seq_stop(struct seq_file *seq, void *v){	struct neigh_seq_state *state = seq->private;	struct neigh_table *tbl = state->tbl;	read_unlock_bh(&tbl->lock);}EXPORT_SYMBOL_GPL( myneigh_seq_stop );static void *myneigh_stat_seq_start(struct seq_file *seq, loff_t *pos){	struct proc_dir_entry *pde = seq->private;	struct neigh_table *tbl = pde->data;	int cpu;	if (*pos == 0)		return SEQ_START_TOKEN;		for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {		if (!cpu_possible(cpu))			continue;		*pos = cpu+1;		return per_cpu_ptr(tbl->stats, cpu);	}	return NULL;}static void *myneigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct proc_dir_entry *pde = seq->private;	struct neigh_table *tbl = pde->data;	int cpu;	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {		if (!cpu_possible(cpu))			continue;		*pos = cpu+1;		return per_cpu_ptr(tbl->stats, cpu);	}	return NULL;}static void myneigh_stat_seq_stop(struct seq_file *seq, void *v){}static int myneigh_stat_seq_show(struct seq_file *seq, void *v){	struct proc_dir_entry *pde = seq->private;	struct neigh_table *tbl = pde->data;	struct neigh_statistics *st = v;	if (v == SEQ_START_TOKEN) {		seq_printf(seq, "entries  allocs destroys hash_grows"						"  lookups hits  res_failed  rcv_probes_mcast"						" rcv_probes_ucast  periodic_gc_runs forced_gc_runs\n");		return 0;	}	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "			"%08lx %08lx  %08lx %08lx\n",		   atomic_read(&tbl->entries), st->allocs,		   st->destroys, st->hash_grows, st->lookups,		   st->hits, st->res_failed, st->rcv_probes_mcast,		   st->rcv_probes_ucast, st->periodic_gc_runs, st->forced_gc_runs );	return 0;}static struct seq_operations myneigh_stat_seq_ops = {	.start	= myneigh_stat_seq_start,	.next	= myneigh_stat_seq_next,	.stop	= myneigh_stat_seq_stop,	.show	= myneigh_stat_seq_show,};static int myneigh_stat_seq_open( struct inode *inode, struct file *file ){	int ret = seq_open(file, &myneigh_stat_seq_ops);	if (!ret) {		struct seq_file *sf = file->private_data;		sf->private = PDE(inode);	}	return ret;};static struct file_operations myneigh_stat_seq_fops = {	.owner	 = THIS_MODULE,	.open 	 = myneigh_stat_seq_open,	.read	 = seq_read,	.llseek	 = seq_lseek,	.release = seq_release,};#endif /* CONFIG_PROC_FS */static int myneigh_blackhole(struct sk_buff *skb){	kfree_skb(skb);	return -ENETDOWN;}static void myneigh_hash_free(struct neighbour **hash, unsigned int entries){	unsigned long size = entries * sizeof(struct neighbour *);	if (size <= PAGE_SIZE)		kfree(hash);	else		free_pages((unsigned long)hash, get_order(size));}static int myneigh_forced_gc(struct neigh_table *tbl){	int shrunk = 0;	int i;	NEIGH_CACHE_STAT_INC( tbl, forced_gc_runs );	write_lock_bh(&tbl->lock);	for( i = 0; i <= tbl->hash_mask; i++ ){		struct neighbour *n, **np;		np = &tbl->hash_buckets[i];		while ((n = *np) != NULL) {			write_lock( &n->lock );			if( atomic_read(&n->refcnt) == 1 && !(n->nud_state & NUD_PERMANENT) ){				*np	= n->next;				n->dead = 1;				shrunk	= 1;				write_unlock( &n->lock );				myneigh_release( n );				continue;			}			write_unlock(&n->lock);			np = &n->next;		}	}	tbl->last_flush = jiffies;	write_unlock_bh(&tbl->lock);	return shrunk;}static void myneigh_suspect(struct neighbour *neigh){	struct hh_cache *hh;	PR_DEBUG("neigh %p is suspected.\n", neigh);	neigh->output = neigh->ops->output;	for( hh = neigh->hh; hh; hh = hh->hh_next )		hh->hh_output = neigh->ops->output;}static void myneigh_connect(struct neighbour *neigh){	struct hh_cache *hh;	PR_DEBUG("neigh %p is connected.\n", neigh);	neigh->output = neigh->ops->connected_output;	for (hh = neigh->hh; hh; hh = hh->hh_next)		hh->hh_output = neigh->ops->hh_output;}static __inline__ int myneigh_max_probes( struct neighbour *n ){	struct neigh_parms *p = n->parms;	return ( n->nud_state & NUD_PROBE ? p->ucast_probes :					p->ucast_probes + p->app_probes + p->mcast_probes);}static void myneigh_timer_handler(unsigned long arg){	unsigned long now, next;	struct neighbour *neigh = (struct neighbour *)arg;	unsigned state;	int notify = 0;	write_lock(&neigh->lock);	state = neigh->nud_state;	now = jiffies;	next = now + HZ;	if( !(state & NUD_IN_TIMER) )		goto out;	if( state & NUD_REACHABLE ){		if( time_before_eq(now, 				   neigh->confirmed + neigh->parms->reachable_time)) {			PR_DEBUG("neigh %p is still alive.\n", neigh);			next = neigh->confirmed + neigh->parms->reachable_time;		}else if( time_before_eq(now, neigh->used + neigh->parms->delay_probe_time) ){			PR_DEBUG("neigh %p is delayed.\n", neigh);			neigh->nud_state = NUD_DELAY;			myneigh_suspect(neigh);			next = now + neigh->parms->delay_probe_time;		}else{			PR_DEBUG("neigh %p is suspected.\n", neigh);			myneigh_release( neigh );		//tmp code FIXME			neigh->nud_state = NUD_STALE;			myneigh_suspect(neigh);		}	}else if( state & NUD_DELAY ){		if (time_before_eq(now, 				   neigh->confirmed + neigh->parms->delay_probe_time)) {			PR_DEBUG("neigh %p is now reachable.\n", neigh);			neigh->nud_state = NUD_REACHABLE;			myneigh_connect(neigh);			next = neigh->confirmed + neigh->parms->reachable_time;		}else{			PR_DEBUG("neigh %p is probed.\n", neigh);			neigh->nud_state = NUD_PROBE;			atomic_set(&neigh->probes, 0);			next = now + neigh->parms->retrans_time;		}	}else{		next = now + neigh->parms->retrans_time;	}	PR_DEBUG( "net time: %lu\n", next );	if( (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&					atomic_read(&neigh->probes) >= myneigh_max_probes(neigh) ){		struct sk_buff *skb;		neigh->nud_state = NUD_FAILED;		notify = 1;		NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);		PR_ERR("neigh %p is failed.\n", neigh);		myneigh_release( neigh );			//TMPCODE FIXME!!		while( neigh->nud_state == NUD_FAILED &&		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL ){			write_unlock(&neigh->lock);			neigh->ops->error_report( neigh, skb );				dev_put( skb->dev );				//TMPCODE FIXME!!			write_lock(&neigh->lock);		}		skb_queue_purge(&neigh->arp_queue);	}	if (neigh->nud_state & NUD_IN_TIMER) {		if( time_before(next, jiffies + HZ/2) )			next = jiffies + HZ/2;		if( !mod_timer(&neigh->timer, next) )			neigh_hold(neigh);		PR_DEBUG( "neigh: %d\n", atomic_read( &neigh->refcnt ) );		PR_DEBUG( "next time: %lu\n", next );	}	if( neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE) ){		struct sk_buff *skb = skb_peek( &neigh->arp_queue );		if( skb )			skb_get(skb);		write_unlock( &neigh->lock );		neigh->ops->solicit( neigh, skb );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -