📄 neighbour.c
字号:
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 + -