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

📄 fib_hash.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
out_free_new_fa:	kmem_cache_free(fn_alias_kmem, new_fa);out:	fib_release_info(fi);	return err;}static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg){	struct fn_hash *table = (struct fn_hash*)tb->tb_data;	struct fib_node *f;	struct fib_alias *fa, *fa_to_delete;	struct fn_zone *fz;	__be32 key;	if (cfg->fc_dst_len > 32)		return -EINVAL;	if ((fz  = table->fn_zones[cfg->fc_dst_len]) == NULL)		return -ESRCH;	key = 0;	if (cfg->fc_dst) {		if (cfg->fc_dst & ~FZ_MASK(fz))			return -EINVAL;		key = fz_key(cfg->fc_dst, fz);	}	f = fib_find_node(fz, key);	if (!f)		fa = NULL;	else		fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0);	if (!fa)		return -ESRCH;	fa_to_delete = NULL;	fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);	list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {		struct fib_info *fi = fa->fa_info;		if (fa->fa_tos != cfg->fc_tos)			break;		if ((!cfg->fc_type ||		     fa->fa_type == cfg->fc_type) &&		    (cfg->fc_scope == RT_SCOPE_NOWHERE ||		     fa->fa_scope == cfg->fc_scope) &&		    (!cfg->fc_protocol ||		     fi->fib_protocol == cfg->fc_protocol) &&		    fib_nh_match(cfg, fi) == 0) {			fa_to_delete = fa;			break;		}	}	if (fa_to_delete) {		int kill_fn;		fa = fa_to_delete;		rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len,			  tb->tb_id, &cfg->fc_nlinfo, 0);		kill_fn = 0;		write_lock_bh(&fib_hash_lock);		list_del(&fa->fa_list);		if (list_empty(&f->fn_alias)) {			hlist_del(&f->fn_hash);			kill_fn = 1;		}		fib_hash_genid++;		write_unlock_bh(&fib_hash_lock);		if (fa->fa_state & FA_S_ACCESSED)			rt_cache_flush(-1);		fn_free_alias(fa);		if (kill_fn) {			fn_free_node(f);			fz->fz_nent--;		}		return 0;	}	return -ESRCH;}static int fn_flush_list(struct fn_zone *fz, int idx){	struct hlist_head *head = &fz->fz_hash[idx];	struct hlist_node *node, *n;	struct fib_node *f;	int found = 0;	hlist_for_each_entry_safe(f, node, n, head, fn_hash) {		struct fib_alias *fa, *fa_node;		int kill_f;		kill_f = 0;		list_for_each_entry_safe(fa, fa_node, &f->fn_alias, fa_list) {			struct fib_info *fi = fa->fa_info;			if (fi && (fi->fib_flags&RTNH_F_DEAD)) {				write_lock_bh(&fib_hash_lock);				list_del(&fa->fa_list);				if (list_empty(&f->fn_alias)) {					hlist_del(&f->fn_hash);					kill_f = 1;				}				fib_hash_genid++;				write_unlock_bh(&fib_hash_lock);				fn_free_alias(fa);				found++;			}		}		if (kill_f) {			fn_free_node(f);			fz->fz_nent--;		}	}	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;	for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {		int i;		for (i = fz->fz_divisor - 1; i >= 0; i--)			found += fn_flush_list(fz, i);	}	return found;}static inline intfn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,		     struct fib_table *tb,		     struct fn_zone *fz,		     struct hlist_head *head){	struct hlist_node *node;	struct fib_node *f;	int i, s_i;	s_i = cb->args[4];	i = 0;	hlist_for_each_entry(f, node, head, fn_hash) {		struct fib_alias *fa;		list_for_each_entry(fa, &f->fn_alias, fa_list) {			if (i < s_i)				goto next;			if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,					  cb->nlh->nlmsg_seq,					  RTM_NEWROUTE,					  tb->tb_id,					  fa->fa_type,					  fa->fa_scope,					  f->fn_key,					  fz->fz_order,					  fa->fa_tos,					  fa->fa_info,					  NLM_F_MULTI) < 0) {				cb->args[4] = i;				return -1;			}		next:			i++;		}	}	cb->args[4] = 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;	if (fz->fz_hash == NULL)		return skb->len;	s_h = cb->args[3];	for (h = s_h; h < fz->fz_divisor; h++) {		if (hlist_empty(&fz->fz_hash[h]))			continue;		if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) {			cb->args[3] = h;			return -1;		}		memset(&cb->args[4], 0,		       sizeof(cb->args) - 4*sizeof(cb->args[0]));	}	cb->args[3] = 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[2];	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 (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {			cb->args[2] = m;			read_unlock(&fib_hash_lock);			return -1;		}		memset(&cb->args[3], 0,		       sizeof(cb->args) - 3*sizeof(cb->args[0]));	}	read_unlock(&fib_hash_lock);	cb->args[2] = m;	return skb->len;}#ifdef CONFIG_IP_MULTIPLE_TABLESstruct fib_table * fib_hash_init(u32 id)#elsestruct fib_table * __init fib_hash_init(u32 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);	if (fn_alias_kmem == NULL)		fn_alias_kmem = kmem_cache_create("ip_fib_alias",						  sizeof(struct fib_alias),						  0, SLAB_HWCACHE_ALIGN,						  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;	memset(tb->tb_data, 0, sizeof(struct fn_hash));	return tb;}/* ------------------------------------------------------------------------ */#ifdef CONFIG_PROC_FSstruct fib_iter_state {	struct fn_zone	*zone;	int		bucket;	struct hlist_head *hash_head;	struct fib_node *fn;	struct fib_alias *fa;	loff_t pos;	unsigned int genid;	int valid;};static struct fib_alias *fib_get_first(struct seq_file *seq){	struct fib_iter_state *iter = seq->private;	struct fn_hash *table = (struct fn_hash *) ip_fib_main_table->tb_data;	iter->bucket    = 0;	iter->hash_head = NULL;	iter->fn        = NULL;	iter->fa        = NULL;	iter->pos	= 0;	iter->genid	= fib_hash_genid;	iter->valid	= 1;	for (iter->zone = table->fn_zone_list; iter->zone;	     iter->zone = iter->zone->fz_next) {		int maxslot;		if (!iter->zone->fz_nent)			continue;		iter->hash_head = iter->zone->fz_hash;		maxslot = iter->zone->fz_divisor;		for (iter->bucket = 0; iter->bucket < maxslot;		     ++iter->bucket, ++iter->hash_head) {			struct hlist_node *node;			struct fib_node *fn;			hlist_for_each_entry(fn,node,iter->hash_head,fn_hash) {				struct fib_alias *fa;				list_for_each_entry(fa,&fn->fn_alias,fa_list) {					iter->fn = fn;					iter->fa = fa;					goto out;				}			}		}	}out:	return iter->fa;}static struct fib_alias *fib_get_next(struct seq_file *seq){	struct fib_iter_state *iter = seq->private;	struct fib_node *fn;	struct fib_alias *fa;	/* Advance FA, if any. */	fn = iter->fn;	fa = iter->fa;	if (fa) {		BUG_ON(!fn);		list_for_each_entry_continue(fa, &fn->fn_alias, fa_list) {			iter->fa = fa;			goto out;		}	}	fa = iter->fa = NULL;	/* Advance FN. */	if (fn) {		struct hlist_node *node = &fn->fn_hash;		hlist_for_each_entry_continue(fn, node, fn_hash) {			iter->fn = fn;			list_for_each_entry(fa, &fn->fn_alias, fa_list) {				iter->fa = fa;				goto out;			}		}	}	fn = iter->fn = NULL;	/* Advance hash chain. */	if (!iter->zone)		goto out;	for (;;) {		struct hlist_node *node;		int maxslot;		maxslot = iter->zone->fz_divisor;		while (++iter->bucket < maxslot) {			iter->hash_head++;			hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) {				list_for_each_entry(fa, &fn->fn_alias, fa_list) {					iter->fn = fn;					iter->fa = fa;					goto out;				}			}		}		iter->zone = iter->zone->fz_next;		if (!iter->zone)			goto out;		iter->bucket = 0;		iter->hash_head = iter->zone->fz_hash;		hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) {			list_for_each_entry(fa, &fn->fn_alias, fa_list) {				iter->fn = fn;				iter->fa = fa;				goto out;			}		}	}out:	iter->pos++;	return fa;}static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos){	struct fib_iter_state *iter = seq->private;	struct fib_alias *fa;	if (iter->valid && pos >= iter->pos && iter->genid == fib_hash_genid) {		fa   = iter->fa;		pos -= iter->pos;	} else		fa = fib_get_first(seq);	if (fa)		while (pos && (fa = fib_get_next(seq)))			--pos;	return pos ? NULL : fa;}static void *fib_seq_start(struct seq_file *seq, loff_t *pos){	void *v = NULL;	read_lock(&fib_hash_lock);	if (ip_fib_main_table)		v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;	return v;}static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos){	++*pos;	return v == SEQ_START_TOKEN ? fib_get_first(seq) : fib_get_next(seq);}static void fib_seq_stop(struct seq_file *seq, void *v){	read_unlock(&fib_hash_lock);}static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi){	static const unsigned type2flags[RTN_MAX + 1] = {		[7] = RTF_REJECT, [8] = RTF_REJECT,	};	unsigned flags = type2flags[type];	if (fi && fi->fib_nh->nh_gw)		flags |= RTF_GATEWAY;	if (mask == htonl(0xFFFFFFFF))		flags |= RTF_HOST;	flags |= RTF_UP;	return flags;}/* *	This outputs /proc/net/route. * *	It always works in backward compatibility mode. *	The format of the file is not supposed to be changed. */static int fib_seq_show(struct seq_file *seq, void *v){	struct fib_iter_state *iter;	char bf[128];	__be32 prefix, mask;	unsigned flags;	struct fib_node *f;	struct fib_alias *fa;	struct fib_info *fi;	if (v == SEQ_START_TOKEN) {		seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "			   "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"			   "\tWindow\tIRTT");		goto out;	}	iter	= seq->private;	f	= iter->fn;	fa	= iter->fa;	fi	= fa->fa_info;	prefix	= f->fn_key;	mask	= FZ_MASK(iter->zone);	flags	= fib_flag_trans(fa->fa_type, mask, fi);	if (fi)		snprintf(bf, sizeof(bf),			 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",			 fi->fib_dev ? fi->fib_dev->name : "*", prefix,			 fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,			 mask, (fi->fib_advmss ? fi->fib_advmss + 40 : 0),			 fi->fib_window,			 fi->fib_rtt >> 3);	else		snprintf(bf, sizeof(bf),			 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",			 prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0);	seq_printf(seq, "%-127s\n", bf);out:	return 0;}static const struct seq_operations fib_seq_ops = {	.start  = fib_seq_start,	.next   = fib_seq_next,	.stop   = fib_seq_stop,	.show   = fib_seq_show,};static int fib_seq_open(struct inode *inode, struct file *file){	return seq_open_private(file, &fib_seq_ops,			sizeof(struct fib_iter_state));}static const struct file_operations fib_seq_fops = {	.owner		= THIS_MODULE,	.open           = fib_seq_open,	.read           = seq_read,	.llseek         = seq_lseek,	.release	= seq_release_private,};int __init fib_proc_init(void){	if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_seq_fops))		return -ENOMEM;	return 0;}void __init fib_proc_exit(void){	proc_net_remove(&init_net, "route");}#endif /* CONFIG_PROC_FS */

⌨️ 快捷键说明

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