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

📄 fib_hash.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (dst & ~FZ_MASK(fz))			return -EINVAL;		key = fz_key(dst, fz);	}	if  ((fi = fib_create_info(r, rta, n, &err)) == NULL)		return err;#ifdef CONFIG_IP_ROUTE_LARGE_TABLES	if (fz->fz_nent > (fz->fz_divisor<<2) &&	    fz->fz_divisor < FZ_MAX_DIVISOR &&	    (z==32 || (1<<z) > fz->fz_divisor))		fn_rehash_zone(fz);#endif	fp = fz_chain_p(key, fz);	/*	 * Scan list to find the first route with the same destination	 */	FIB_SCAN(f, fp) {		if (fn_key_leq(key,f->fn_key))			break;	}#ifdef CONFIG_IP_ROUTE_TOS	/*	 * Find route with the same destination and tos.	 */	FIB_SCAN_KEY(f, fp, key) {		if (f->fn_tos <= tos)			break;	}#endif	del_fp = NULL;	if (f && (f->fn_state&FN_S_ZOMBIE) &&#ifdef CONFIG_IP_ROUTE_TOS	    f->fn_tos == tos &&#endif	    fn_key_eq(f->fn_key, key)) {		del_fp = fp;		fp = &f->fn_next;		f = *fp;		goto create;	}	FIB_SCAN_TOS(f, fp, key, tos) {		if (fi->fib_priority <= FIB_INFO(f)->fib_priority)			break;	}	/* Now f==*fp points to the first node with the same	   keys [prefix,tos,priority], if such key already	   exists or to the node, before which we will insert new one.	 */	if (f && #ifdef CONFIG_IP_ROUTE_TOS	    f->fn_tos == tos &&#endif	    fn_key_eq(f->fn_key, key) &&	    fi->fib_priority == FIB_INFO(f)->fib_priority) {		struct fib_node **ins_fp;		err = -EEXIST;		if (n->nlmsg_flags&NLM_F_EXCL)			goto out;		if (n->nlmsg_flags&NLM_F_REPLACE) {			del_fp = fp;			fp = &f->fn_next;			f = *fp;			goto replace;		}		ins_fp = fp;		err = -EEXIST;		FIB_SCAN_TOS(f, fp, key, tos) {			if (fi->fib_priority != FIB_INFO(f)->fib_priority)				break;			if (f->fn_type == type && f->fn_scope == r->rtm_scope			    && FIB_INFO(f) == fi)				goto out;		}		if (!(n->nlmsg_flags&NLM_F_APPEND)) {			fp = ins_fp;			f = *fp;		}	}create:	err = -ENOENT;	if (!(n->nlmsg_flags&NLM_F_CREATE))		goto out;replace:	err = -ENOBUFS;	new_f = kmem_cache_alloc(fn_hash_kmem, SLAB_KERNEL);	if (new_f == NULL)		goto out;	memset(new_f, 0, sizeof(struct fib_node));	new_f->fn_key = key;#ifdef CONFIG_IP_ROUTE_TOS	new_f->fn_tos = tos;#endif	new_f->fn_type = type;	new_f->fn_scope = r->rtm_scope;	FIB_INFO(new_f) = fi;	/*	 * Insert new entry to the list.	 */	new_f->fn_next = f;	write_lock_bh(&fib_hash_lock);	*fp = new_f;	write_unlock_bh(&fib_hash_lock);	fz->fz_nent++;	if (del_fp) {		f = *del_fp;		/* Unlink replaced node */		write_lock_bh(&fib_hash_lock);		*del_fp = f->fn_next;		write_unlock_bh(&fib_hash_lock);		if (!(f->fn_state&FN_S_ZOMBIE))			rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);		if (f->fn_state&FN_S_ACCESSED)			rt_cache_flush(-1);		fn_free_node(f);		fz->fz_nent--;	} else {		rt_cache_flush(-1);	}	rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->tb_id, n, req);	return 0;out:	fib_release_info(fi);	return err;}static intfn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,		struct nlmsghdr *n, struct netlink_skb_parms *req){	struct fn_hash *table = (struct fn_hash*)tb->tb_data;	struct fib_node **fp, **del_fp, *f;	int z = r->rtm_dst_len;	struct fn_zone *fz;	fn_key_t key;	int matched;#ifdef CONFIG_IP_ROUTE_TOS	u8 tos = r->rtm_tos;#endifFTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?       *(u32*)rta->rta_dst : 0, z, rta->rta_oif ? *rta->rta_oif : -1);	if (z > 32)		return -EINVAL;	if ((fz  = table->fn_zones[z]) == NULL)		return -ESRCH;	fz_key_0(key);	if (rta->rta_dst) {		u32 dst;		memcpy(&dst, rta->rta_dst, 4);		if (dst & ~FZ_MASK(fz))			return -EINVAL;		key = fz_key(dst, fz);	}	fp = fz_chain_p(key, fz);	FIB_SCAN(f, fp) {		if (fn_key_eq(f->fn_key, key))			break;		if (fn_key_leq(key, f->fn_key)) {			return -ESRCH;		}	}#ifdef CONFIG_IP_ROUTE_TOS	FIB_SCAN_KEY(f, fp, key) {		if (f->fn_tos == tos)			break;	}#endif	matched = 0;	del_fp = NULL;	FIB_SCAN_TOS(f, fp, key, tos) {		struct fib_info * fi = FIB_INFO(f);		if (f->fn_state&FN_S_ZOMBIE) {			return -ESRCH;		}		matched++;		if (del_fp == NULL &&		    (!r->rtm_type || f->fn_type == r->rtm_type) &&		    (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&		    (!r->rtm_protocol || fi->fib_protocol == r->rtm_protocol) &&		    fib_nh_match(r, n, rta, fi) == 0)			del_fp = fp;	}	if (del_fp) {		f = *del_fp;		rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);		if (matched != 1) {			write_lock_bh(&fib_hash_lock);			*del_fp = f->fn_next;			write_unlock_bh(&fib_hash_lock);			if (f->fn_state&FN_S_ACCESSED)				rt_cache_flush(-1);			fn_free_node(f);			fz->fz_nent--;		} else {			f->fn_state |= FN_S_ZOMBIE;			if (f->fn_state&FN_S_ACCESSED) {				f->fn_state &= ~FN_S_ACCESSED;				rt_cache_flush(-1);			}			if (++fib_hash_zombies > 128)				fib_flush();		}		return 0;	}	return -ESRCH;}extern __inline__ intfn_flush_list(struct fib_node ** fp, int z, struct fn_hash *table){	int found = 0;	struct fib_node *f;	while ((f = *fp) != NULL) {		struct fib_info *fi = FIB_INFO(f);		if (fi && ((f->fn_state&FN_S_ZOMBIE) || (fi->fib_flags&RTNH_F_DEAD))) {			write_lock_bh(&fib_hash_lock);			*fp = f->fn_next;			write_unlock_bh(&fib_hash_lock);			fn_free_node(f);			found++;			continue;		}		fp = &f->fn_next;	}	return found;}static int fn_hash_flush(struct fib_table *tb){	struct fn_hash *table = (struct fn_hash*)tb->tb_data;	struct fn_zone *fz;	int found = 0;	fib_hash_zombies = 0;	for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {		int i;		int tmp = 0;		for (i=fz->fz_divisor-1; i>=0; i--)			tmp += fn_flush_list(&fz->fz_hash[i], fz->fz_order, table);		fz->fz_nent -= tmp;		found += tmp;	}	return found;}#ifdef CONFIG_PROC_FSstatic int fn_hash_get_info(struct fib_table *tb, char *buffer, int first, int count){	struct fn_hash *table = (struct fn_hash*)tb->tb_data;	struct fn_zone *fz;	int pos = 0;	int n = 0;	read_lock(&fib_hash_lock);	for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {		int i;		struct fib_node *f;		int maxslot = fz->fz_divisor;		struct fib_node **fp = fz->fz_hash;		if (fz->fz_nent == 0)			continue;		if (pos + fz->fz_nent <= first) {			pos += fz->fz_nent;			continue;		}		for (i=0; i < maxslot; i++, fp++) {			for (f = *fp; f; f = f->fn_next) {				if (++pos <= first)					continue;				fib_node_get_info(f->fn_type,						  f->fn_state&FN_S_ZOMBIE,						  FIB_INFO(f),						  fz_prefix(f->fn_key, fz),						  FZ_MASK(fz), buffer);				buffer += 128;				if (++n >= count)					goto out;			}		}	}out:	read_unlock(&fib_hash_lock);  	return n;}#endifstatic __inline__ intfn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,		     struct fib_table *tb,		     struct fn_zone *fz,		     struct fib_node *f){	int i, s_i;	s_i = cb->args[3];	for (i=0; f; i++, f=f->fn_next) {		if (i < s_i) continue;		if (f->fn_state&FN_S_ZOMBIE) continue;		if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,				  RTM_NEWROUTE,				  tb->tb_id, (f->fn_state&FN_S_ZOMBIE) ? 0 : f->fn_type, f->fn_scope,				  &f->fn_key, fz->fz_order, f->fn_tos,				  f->fn_info) < 0) {			cb->args[3] = i;			return -1;		}	}	cb->args[3] = i;	return skb->len;}static __inline__ intfn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,		   struct fib_table *tb,		   struct fn_zone *fz){	int h, s_h;	s_h = cb->args[2];	for (h=0; h < fz->fz_divisor; h++) {		if (h < s_h) continue;		if (h > s_h)			memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));		if (fz->fz_hash == NULL || fz->fz_hash[h] == NULL)			continue;		if (fn_hash_dump_bucket(skb, cb, tb, fz, fz->fz_hash[h]) < 0) {			cb->args[2] = h;			return -1;		}	}	cb->args[2] = h;	return skb->len;}static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb){	int m, s_m;	struct fn_zone *fz;	struct fn_hash *table = (struct fn_hash*)tb->tb_data;	s_m = cb->args[1];	read_lock(&fib_hash_lock);	for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {		if (m < s_m) continue;		if (m > s_m)			memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));		if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {			cb->args[1] = m;			read_unlock(&fib_hash_lock);			return -1;		}	}	read_unlock(&fib_hash_lock);	cb->args[1] = m;	return skb->len;}static void rtmsg_fib(int event, struct fib_node* f, int z, int tb_id,		      struct nlmsghdr *n, struct netlink_skb_parms *req){	struct sk_buff *skb;	u32 pid = req ? req->pid : 0;	int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);	skb = alloc_skb(size, GFP_KERNEL);	if (!skb)		return;	if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id,			  f->fn_type, f->fn_scope, &f->fn_key, z, f->fn_tos,			  FIB_INFO(f)) < 0) {		kfree_skb(skb);		return;	}	NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE;	if (n->nlmsg_flags&NLM_F_ECHO)		atomic_inc(&skb->users);	netlink_broadcast(rtnl, skb, pid, RTMGRP_IPV4_ROUTE, GFP_KERNEL);	if (n->nlmsg_flags&NLM_F_ECHO)		netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);}#ifdef CONFIG_IP_MULTIPLE_TABLESstruct fib_table * fib_hash_init(int id)#elsestruct fib_table * __init fib_hash_init(int id)#endif{	struct fib_table *tb;	if (fn_hash_kmem == NULL)		fn_hash_kmem = kmem_cache_create("ip_fib_hash",						 sizeof(struct fib_node),						 0, SLAB_HWCACHE_ALIGN,						 NULL, NULL);	tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash), GFP_KERNEL);	if (tb == NULL)		return NULL;	tb->tb_id = id;	tb->tb_lookup = fn_hash_lookup;	tb->tb_insert = fn_hash_insert;	tb->tb_delete = fn_hash_delete;	tb->tb_flush = fn_hash_flush;	tb->tb_select_default = fn_hash_select_default;	tb->tb_dump = fn_hash_dump;#ifdef CONFIG_PROC_FS	tb->tb_get_info = fn_hash_get_info;#endif	memset(tb->tb_data, 0, sizeof(struct fn_hash));	return tb;}

⌨️ 快捷键说明

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