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

📄 neighbour.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	expire = tbl->parms.base_reachable_time >> 1;	expire /= (tbl->hash_mask + 1);	if (!expire)		expire = 1; 	mod_timer(&tbl->gc_timer, now + expire);	//PR_DEBUG( "expire: %lus\n", expire/HZ );	write_unlock(&tbl->lock);}static void myneigh_proxy_process(unsigned long arg){	struct neigh_table *tbl = (struct neigh_table *)arg;	long sched_next = 0;	unsigned long now = jiffies;	struct sk_buff *skb;	spin_lock(&tbl->proxy_queue.lock);	skb = tbl->proxy_queue.next;	while( skb != (struct sk_buff *)&tbl->proxy_queue ){		struct sk_buff *back = skb;		long tdif = NEIGH_CB(back)->sched_next - now;		skb = skb->next;		if( tdif <= 0 ){			struct net_device *dev = back->dev;			__skb_unlink( back, &tbl->proxy_queue );			if( tbl->proxy_redo && netif_running(dev) )				tbl->proxy_redo(back);			else				kfree_skb( back );			dev_put(dev);		}else if( !sched_next || tdif < sched_next )			sched_next = tdif;	}	del_timer(&tbl->proxy_timer);	if (sched_next)		mod_timer(&tbl->proxy_timer, jiffies + sched_next);	spin_unlock(&tbl->proxy_queue.lock);}struct neigh_parms *myneigh_parms_alloc(struct net_device *dev,				struct neigh_table *tbl){	struct neigh_parms *p = kmalloc(sizeof(*p), GFP_KERNEL);	if( p ){		memcpy( p, &tbl->parms, sizeof(*p) );		p->tbl = tbl;		atomic_set(&p->refcnt, 1);		INIT_RCU_HEAD(&p->rcu_head);		p->reachable_time = neigh_rand_reach_time( p->base_reachable_time );		if (dev) {			if( dev->neigh_setup && dev->neigh_setup(dev, p) ){				kfree(p);				return NULL;			}			dev_hold(dev);			p->dev = dev;		}		p->sysctl_table = NULL;		write_lock_bh( &tbl->lock );		p->next			= tbl->parms.next;		tbl->parms.next = p;		write_unlock_bh( &tbl->lock );	}	return p;}static void myneigh_rcu_free_parms( struct rcu_head *head ){	struct neigh_parms *parms = container_of(head, struct neigh_parms, rcu_head);	myneigh_parms_put(parms);}void myneigh_parms_release( struct neigh_table *tbl, struct neigh_parms *parms ){	struct neigh_parms **p;	if( !parms || parms == &tbl->parms )		return;	write_lock_bh(&tbl->lock);	for( p = &tbl->parms.next; *p; p = &(*p)->next) {		if( *p == parms ){			*p = parms->next;			parms->dead = 1;			write_unlock_bh(&tbl->lock);			if( parms->dev )				dev_put( parms->dev );			call_rcu( &parms->rcu_head, myneigh_rcu_free_parms );			return;		}	}	write_unlock_bh(&tbl->lock);	PR_ERR( "neigh_parms_release: not found\n" );}static void myneigh_flush_dev(struct neigh_table *tbl, struct net_device *dev){	int i;	for( i = 0; i <= tbl->hash_mask; i++ ){		struct neighbour *n, **np = &tbl->hash_buckets[i];		while( (n = *np) != NULL ){			if( dev && n->dev != dev ){				np = &n->next;				continue;			}			*np = n->next;			write_lock(&n->lock);			myneigh_del_timer(n);			n->dead = 1;			if( atomic_read(&n->refcnt) != 1 ){				skb_queue_purge( &n->arp_queue );				n->output = myneigh_blackhole;				if( n->nud_state & NUD_VALID )					n->nud_state = NUD_NOARP;				else					n->nud_state = NUD_NONE;				PR_WARN("neigh %p is stray.\n", n);			}			write_unlock(&n->lock);			myneigh_release(n);		}	}}static int mypneigh_ifdown( struct neigh_table *tbl, struct net_device *dev ){	struct pneigh_entry *n, **np;	u32 h;	for (h = 0; h <= PNEIGH_HASHMASK; h++) {		np = &tbl->phash_buckets[h];		while ((n = *np) != NULL) {			if (!dev || n->dev == dev) {				*np = n->next;				if( tbl->pdestructor )					tbl->pdestructor(n);				if( n->dev )					dev_put( n->dev );				kfree(n);				continue;			}			np = &n->next;		}	}	return -ENOENT;}static void mypneigh_queue_purge( struct sk_buff_head *list ){	struct sk_buff *skb;	while( (skb = skb_dequeue(list)) != NULL ){		dev_put(skb->dev);		kfree_skb(skb);	}}int myneigh_ifdown( struct neigh_table *tbl, struct net_device *dev ){	write_lock_bh( &tbl->lock );	myneigh_flush_dev( tbl, dev );	mypneigh_ifdown( tbl, dev );	write_unlock_bh( &tbl->lock );	del_timer_sync( &tbl->proxy_timer );	mypneigh_queue_purge( &tbl->proxy_queue );	return 0;}static __inline__ void myneigh_update_hhs(struct neighbour *neigh){	struct hh_cache *hh;	void (*update)(struct hh_cache*, struct net_device*, unsigned char *) =			neigh->dev->header_cache_update;	if( update ){		for (hh = neigh->hh; hh; hh = hh->hh_next) {			write_lock_bh(&hh->hh_lock);			update(hh, neigh->dev, neigh->ha);			write_unlock_bh(&hh->hh_lock);		}	}}int myneigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,				u32 flags){	u8 old;	int err;	struct net_device *dev;	int update_isrouter = 0;	write_lock_bh( &neigh->lock );	dev    = neigh->dev;	old    = neigh->nud_state;	err    = -EPERM;	if( !(flags & NEIGH_UPDATE_F_ADMIN) && (old & (NUD_NOARP | NUD_PERMANENT)) )		goto out;	if( !(new & NUD_VALID) ){		myneigh_del_timer( neigh );		if( old & NUD_CONNECTED )			myneigh_suspect(neigh);		neigh->nud_state = new;		err = 0;		goto out;	}	if( !dev->addr_len ){		lladdr = neigh->ha;	}else if( lladdr ){		if( (old & NUD_VALID) && !memcmp(lladdr, neigh->ha, dev->addr_len))			lladdr = neigh->ha;	}else{		err = -EINVAL;		if( !(old & NUD_VALID) )			goto out;		lladdr = neigh->ha;	}	if( new & NUD_CONNECTED )		neigh->confirmed = jiffies;	neigh->updated = jiffies;	err = 0;	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;	if( old & NUD_VALID ){		if( lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE) ){			update_isrouter = 0;			if( (flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) && (old & NUD_CONNECTED) ){				lladdr = neigh->ha;				new = NUD_STALE;			} else				goto out;		} else {			if( lladdr == neigh->ha && new == NUD_STALE &&							((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||							 (old & NUD_CONNECTED)) )				new = old;		}	}	if( new != old ){		myneigh_del_timer( neigh );		if( new & NUD_IN_TIMER ){			neigh_hold( neigh );			myneigh_add_timer(neigh, (jiffies + ((new & NUD_REACHABLE) ? 											neigh->parms->reachable_time : 0)) );		}		neigh->nud_state = new;	}	if( lladdr != neigh->ha ){		memcpy(&neigh->ha, lladdr, dev->addr_len);		myneigh_update_hhs( neigh );		if( !(new & NUD_CONNECTED) )			neigh->confirmed = jiffies - (neigh->parms->base_reachable_time << 1 );	}	if( new == old )		goto out;	if( new & NUD_CONNECTED )		myneigh_connect(neigh);	else		myneigh_suspect(neigh);	if( !(old & NUD_VALID) ){		struct sk_buff *skb;		while( neigh->nud_state & NUD_VALID &&						(skb = __skb_dequeue(&neigh->arp_queue)) != NULL ){			struct neighbour *n1 = neigh;			write_unlock_bh(&neigh->lock);			if( skb->dst && skb->dst->neighbour )				n1 = skb->dst->neighbour;			n1->output(skb);			write_lock_bh(&neigh->lock);		}		skb_queue_purge(&neigh->arp_queue);	}out:	if( update_isrouter ){		neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?				(neigh->flags | NTF_ROUTER) : (neigh->flags & ~NTF_ROUTER);	}	write_unlock_bh(&neigh->lock);	return err;}struct neighbour *myneigh_event_ns( struct neigh_table *tbl,				u8 *lladdr, void *saddr, struct net_device *dev ){	struct neighbour *neigh = __myneigh_lookup(tbl, saddr, dev, lladdr || !dev->addr_len);	if( neigh )		myneigh_update( neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_OVERRIDE );	return neigh;}int myneigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	return 0;}int myneigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	return 0;}int myneigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb){	return 0;}int myneightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb){	return 0;}int myneightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	return 0;}int mypneigh_delete(struct neigh_table *tbl, const void *pkey,		  struct net_device *dev){	return -ENOENT;}struct pneigh_entry * mypneigh_lookup(struct neigh_table *tbl, const void *pkey,				    struct net_device *dev, int creat){	return NULL;}void myneigh_table_init(struct neigh_table *tbl){	unsigned long now = jiffies;	unsigned long phsize;	atomic_set( &tbl->parms.refcnt, 1 );	INIT_RCU_HEAD(&tbl->parms.rcu_head);	tbl->parms.reachable_time = neigh_rand_reach_time( tbl->parms.base_reachable_time );		if( !tbl->kmem_cachep )		tbl->kmem_cachep = kmem_cache_create( tbl->id, tbl->entry_size,						0, SLAB_HWCACHE_ALIGN, NULL, NULL );	if (!tbl->kmem_cachep)		panic("cannot create neighbour cache");	tbl->stats = alloc_percpu(struct neigh_statistics);	if (!tbl->stats)		panic("cannot create neighbour cache statistics");#ifdef CONFIG_PROC_FS	tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat);	if (!tbl->pde) 		panic("cannot create neighbour proc dir entry");	tbl->pde->proc_fops = &myneigh_stat_seq_fops;	tbl->pde->data = tbl;#endif	tbl->hash_mask = 1;	tbl->hash_buckets = myneigh_hash_alloc( tbl->hash_mask + 1 );	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);	tbl->phash_buckets = kmalloc(phsize, GFP_KERNEL);	if (!tbl->hash_buckets || !tbl->phash_buckets)		panic("cannot allocate neighbour cache hashes");	memset(tbl->phash_buckets, 0, phsize);	get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));	rwlock_init( &tbl->lock );	init_timer( &tbl->gc_timer );	tbl->gc_timer.data     = (unsigned long)tbl;	tbl->gc_timer.function = myneigh_periodic_timer;	tbl->gc_timer.expires  = now + 1;	add_timer( &tbl->gc_timer );	init_timer( &tbl->proxy_timer );	tbl->proxy_timer.data	  = (unsigned long)tbl;	tbl->proxy_timer.function = myneigh_proxy_process;	skb_queue_head_init( &tbl->proxy_queue );	tbl->last_flush = now;	tbl->last_rand	= now + tbl->parms.reachable_time * 20;	write_lock( &myneigh_tbl_lock );	tbl->next	= myneigh_tables;	myneigh_tables	= tbl;	write_unlock( &myneigh_tbl_lock );}void myneigh_table_destroy( struct neigh_table *tbl ){	int i;	del_timer( &tbl->gc_timer );	if( tbl->phash_buckets ){		kfree( tbl->phash_buckets );		tbl->phash_buckets = NULL;	}	PR_DEBUG( "the hash_mask: %d\n", tbl->hash_mask );	for( i = 0; i < tbl->hash_mask + 1; i ++ ){		struct neighbour *p1, *p2;		p1 = tbl->hash_buckets[i];		PR_DEBUG( "the p1: %p\n", p1 );		while( p1 != NULL ){			p2 = p1;			p1 = p1->next;			PR_DEEP_DEBUG( "free nighbour: %p\n", p2 );			dev_put( p2->dev );			atomic_set( &(p2->refcnt), 0 );			kmem_cache_free( tbl->kmem_cachep, p2 );		}	}	if( tbl->hash_buckets ){		myneigh_hash_free( tbl->hash_buckets, tbl->hash_mask + 1 );		tbl->hash_buckets = NULL;	}	if( tbl->pde ){		remove_proc_entry( tbl->id, proc_net_stat );		tbl->pde = NULL;	}	if( tbl->stats ){		free_percpu( tbl->stats );		tbl->stats = NULL;	}	if( tbl->kmem_cachep ){		kmem_cache_destroy( tbl->kmem_cachep );		tbl->kmem_cachep = NULL;	}	atomic_set( &tbl->parms.refcnt, 0 );}EXPORT_SYMBOL_GPL( myneigh_table_init );EXPORT_SYMBOL_GPL( myneigh_table_destroy );EXPORT_SYMBOL_GPL( myneigh_resolve_output );EXPORT_SYMBOL_GPL( myneigh_connected_output );EXPORT_SYMBOL_GPL( myneigh_compat_output );EXPORT_SYMBOL_GPL( myneigh_create );EXPORT_SYMBOL_GPL( myneigh_lookup );EXPORT_SYMBOL_GPL( myneigh_parms_alloc );EXPORT_SYMBOL_GPL( myneigh_parms_release );EXPORT_SYMBOL_GPL( myneigh_ifdown );EXPORT_SYMBOL_GPL( myarp_tbl );EXPORT_SYMBOL_GPL( myneigh_event_ns );EXPORT_SYMBOL_GPL( myneigh_update );EXPORT_SYMBOL_GPL( myneigh_destroy );EXPORT_SYMBOL_GPL( mypneigh_delete );EXPORT_SYMBOL_GPL( mypneigh_lookup );

⌨️ 快捷键说明

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