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

📄 fib_trie.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			printk(KERN_WARNING "Fix halve_threshold. Now=%d size=%d bits\n",			       halve_threshold, tn->bits);	}	/* Only one child remains */	if (tn->empty_children == tnode_child_length(tn) - 1)		for (i = 0; i < tnode_child_length(tn); i++) {			struct node *n;			n = tn->child[i];			if (!n)				continue;			/* compress one level */			node_set_parent(n, NULL);			tnode_free(tn);			return n;		}	return (struct node *) tn;}static struct tnode *inflate(struct trie *t, struct tnode *tn){	struct tnode *inode;	struct tnode *oldtnode = tn;	int olen = tnode_child_length(tn);	int i;	pr_debug("In inflate\n");	tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);	if (!tn)		return ERR_PTR(-ENOMEM);	/*	 * Preallocate and store tnodes before the actual work so we	 * don't get into an inconsistent state if memory allocation	 * fails. In case of failure we return the oldnode and  inflate	 * of tnode is ignored.	 */	for (i = 0; i < olen; i++) {		struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);		if (inode &&		    IS_TNODE(inode) &&		    inode->pos == oldtnode->pos + oldtnode->bits &&		    inode->bits > 1) {			struct tnode *left, *right;			t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;			left = tnode_new(inode->key&(~m), inode->pos + 1,					 inode->bits - 1);			if (!left)				goto nomem;			right = tnode_new(inode->key|m, inode->pos + 1,					  inode->bits - 1);			if (!right) {				tnode_free(left);				goto nomem;			}			put_child(t, tn, 2*i, (struct node *) left);			put_child(t, tn, 2*i+1, (struct node *) right);		}	}	for (i = 0; i < olen; i++) {		struct node *node = tnode_get_child(oldtnode, i);		struct tnode *left, *right;		int size, j;		/* An empty child */		if (node == NULL)			continue;		/* A leaf or an internal node with skipped bits */		if (IS_LEAF(node) || ((struct tnode *) node)->pos >		   tn->pos + tn->bits - 1) {			if (tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,					     1) == 0)				put_child(t, tn, 2*i, node);			else				put_child(t, tn, 2*i+1, node);			continue;		}		/* An internal node with two children */		inode = (struct tnode *) node;		if (inode->bits == 1) {			put_child(t, tn, 2*i, inode->child[0]);			put_child(t, tn, 2*i+1, inode->child[1]);			tnode_free(inode);			continue;		}		/* An internal node with more than two children */		/* We will replace this node 'inode' with two new		 * ones, 'left' and 'right', each with half of the		 * original children. The two new nodes will have		 * a position one bit further down the key and this		 * means that the "significant" part of their keys		 * (see the discussion near the top of this file)		 * will differ by one bit, which will be "0" in		 * left's key and "1" in right's key. Since we are		 * moving the key position by one step, the bit that		 * we are moving away from - the bit at position		 * (inode->pos) - is the one that will differ between		 * left and right. So... we synthesize that bit in the		 * two  new keys.		 * The mask 'm' below will be a single "one" bit at		 * the position (inode->pos)		 */		/* Use the old key, but set the new significant		 *   bit to zero.		 */		left = (struct tnode *) tnode_get_child(tn, 2*i);		put_child(t, tn, 2*i, NULL);		BUG_ON(!left);		right = (struct tnode *) tnode_get_child(tn, 2*i+1);		put_child(t, tn, 2*i+1, NULL);		BUG_ON(!right);		size = tnode_child_length(left);		for (j = 0; j < size; j++) {			put_child(t, left, j, inode->child[j]);			put_child(t, right, j, inode->child[j + size]);		}		put_child(t, tn, 2*i, resize(t, left));		put_child(t, tn, 2*i+1, resize(t, right));		tnode_free(inode);	}	tnode_free(oldtnode);	return tn;nomem:	{		int size = tnode_child_length(tn);		int j;		for (j = 0; j < size; j++)			if (tn->child[j])				tnode_free((struct tnode *)tn->child[j]);		tnode_free(tn);		return ERR_PTR(-ENOMEM);	}}static struct tnode *halve(struct trie *t, struct tnode *tn){	struct tnode *oldtnode = tn;	struct node *left, *right;	int i;	int olen = tnode_child_length(tn);	pr_debug("In halve\n");	tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);	if (!tn)		return ERR_PTR(-ENOMEM);	/*	 * Preallocate and store tnodes before the actual work so we	 * don't get into an inconsistent state if memory allocation	 * fails. In case of failure we return the oldnode and halve	 * of tnode is ignored.	 */	for (i = 0; i < olen; i += 2) {		left = tnode_get_child(oldtnode, i);		right = tnode_get_child(oldtnode, i+1);		/* Two nonempty children */		if (left && right) {			struct tnode *newn;			newn = tnode_new(left->key, tn->pos + tn->bits, 1);			if (!newn)				goto nomem;			put_child(t, tn, i/2, (struct node *)newn);		}	}	for (i = 0; i < olen; i += 2) {		struct tnode *newBinNode;		left = tnode_get_child(oldtnode, i);		right = tnode_get_child(oldtnode, i+1);		/* At least one of the children is empty */		if (left == NULL) {			if (right == NULL)    /* Both are empty */				continue;			put_child(t, tn, i/2, right);			continue;		}		if (right == NULL) {			put_child(t, tn, i/2, left);			continue;		}		/* Two nonempty children */		newBinNode = (struct tnode *) tnode_get_child(tn, i/2);		put_child(t, tn, i/2, NULL);		put_child(t, newBinNode, 0, left);		put_child(t, newBinNode, 1, right);		put_child(t, tn, i/2, resize(t, newBinNode));	}	tnode_free(oldtnode);	return tn;nomem:	{		int size = tnode_child_length(tn);		int j;		for (j = 0; j < size; j++)			if (tn->child[j])				tnode_free((struct tnode *)tn->child[j]);		tnode_free(tn);		return ERR_PTR(-ENOMEM);	}}static void trie_init(struct trie *t){	if (!t)		return;	t->size = 0;	rcu_assign_pointer(t->trie, NULL);	t->revision = 0;#ifdef CONFIG_IP_FIB_TRIE_STATS	memset(&t->stats, 0, sizeof(struct trie_use_stats));#endif}/* readside must use rcu_read_lock currently dump routines via get_fa_head and dump */static struct leaf_info *find_leaf_info(struct leaf *l, int plen){	struct hlist_head *head = &l->list;	struct hlist_node *node;	struct leaf_info *li;	hlist_for_each_entry_rcu(li, node, head, hlist)		if (li->plen == plen)			return li;	return NULL;}static inline struct list_head * get_fa_head(struct leaf *l, int plen){	struct leaf_info *li = find_leaf_info(l, plen);	if (!li)		return NULL;	return &li->falh;}static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new){	struct leaf_info *li = NULL, *last = NULL;	struct hlist_node *node;	if (hlist_empty(head)) {		hlist_add_head_rcu(&new->hlist, head);	} else {		hlist_for_each_entry(li, node, head, hlist) {			if (new->plen > li->plen)				break;			last = li;		}		if (last)			hlist_add_after_rcu(&last->hlist, &new->hlist);		else			hlist_add_before_rcu(&new->hlist, &li->hlist);	}}/* rcu_read_lock needs to be hold by caller from readside */static struct leaf *fib_find_node(struct trie *t, u32 key){	int pos;	struct tnode *tn;	struct node *n;	pos = 0;	n = rcu_dereference(t->trie);	while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {		tn = (struct tnode *) n;		check_tnode(tn);		if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {			pos = tn->pos + tn->bits;			n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));		} else			break;	}	/* Case we have found a leaf. Compare prefixes */	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))		return (struct leaf *)n;	return NULL;}static struct node *trie_rebalance(struct trie *t, struct tnode *tn){	int wasfull;	t_key cindex, key = tn->key;	struct tnode *tp;	while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {		cindex = tkey_extract_bits(key, tp->pos, tp->bits);		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));		tn = (struct tnode *) resize (t, (struct tnode *)tn);		tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);		tp = node_parent((struct node *) tn);		if (!tp)			break;		tn = tp;	}	/* Handle last (top) tnode */	if (IS_TNODE(tn))		tn = (struct tnode*) resize(t, (struct tnode *)tn);	return (struct node*) tn;}/* only used from updater-side */static  struct list_head *fib_insert_node(struct trie *t, int *err, u32 key, int plen){	int pos, newpos;	struct tnode *tp = NULL, *tn = NULL;	struct node *n;	struct leaf *l;	int missbit;	struct list_head *fa_head = NULL;	struct leaf_info *li;	t_key cindex;	pos = 0;	n = t->trie;	/* If we point to NULL, stop. Either the tree is empty and we should	 * just put a new leaf in if, or we have reached an empty child slot,	 * and we should just put our new leaf in that.	 * If we point to a T_TNODE, check if it matches our key. Note that	 * a T_TNODE might be skipping any number of bits - its 'pos' need	 * not be the parent's 'pos'+'bits'!	 *	 * If it does match the current key, get pos/bits from it, extract	 * the index from our key, push the T_TNODE and walk the tree.	 *	 * If it doesn't, we have to replace it with a new T_TNODE.	 *	 * If we point to a T_LEAF, it might or might not have the same key	 * as we do. If it does, just change the value, update the T_LEAF's	 * value, and return it.	 * If it doesn't, we need to replace it with a T_TNODE.	 */	while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {		tn = (struct tnode *) n;		check_tnode(tn);		if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {			tp = tn;			pos = tn->pos + tn->bits;			n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));			BUG_ON(n && node_parent(n) != tn);		} else			break;	}	/*	 * n  ----> NULL, LEAF or TNODE	 *	 * tp is n's (parent) ----> NULL or TNODE	 */	BUG_ON(tp && IS_LEAF(tp));	/* Case 1: n is a leaf. Compare prefixes */	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {		struct leaf *l = (struct leaf *) n;		li = leaf_info_new(plen);		if (!li) {			*err = -ENOMEM;			goto err;		}		fa_head = &li->falh;		insert_leaf_info(&l->list, li);		goto done;	}	t->size++;	l = leaf_new();	if (!l) {		*err = -ENOMEM;		goto err;	}	l->key = key;	li = leaf_info_new(plen);	if (!li) {		tnode_free((struct tnode *) l);		*err = -ENOMEM;		goto err;	}	fa_head = &li->falh;	insert_leaf_info(&l->list, li);	if (t->trie && n == NULL) {		/* Case 2: n is NULL, and will just insert a new leaf */		node_set_parent((struct node *)l, tp);		cindex = tkey_extract_bits(key, tp->pos, tp->bits);		put_child(t, (struct tnode *)tp, cindex, (struct node *)l);	} else {		/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */		/*		 *  Add a new tnode here		 *  first tnode need some special handling		 */		if (tp)			pos = tp->pos+tp->bits;		else			pos = 0;		if (n) {			newpos = tkey_mismatch(key, pos, n->key);			tn = tnode_new(n->key, newpos, 1);		} else {			newpos = 0;			tn = tnode_new(key, newpos, 1); /* First tnode */		}		if (!tn) {			free_leaf_info(li);			tnode_free((struct tnode *) l);			*err = -ENOMEM;			goto err;		}		node_set_parent((struct node *)tn, tp);		missbit = tkey_extract_bits(key, newpos, 1);		put_child(t, tn, missbit, (struct node *)l);		put_child(t, tn, 1-missbit, n);		if (tp) {			cindex = tkey_extract_bits(key, tp->pos, tp->bits);			put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);		} else {			rcu_assign_pointer(t->trie, (struct node *)tn); /* First tnode */			tp = tn;		}	}	if (tp && tp->pos + tp->bits > 32)		printk(KERN_WARNING "fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",		       tp, tp->pos, tp->bits, key, plen);	/* Rebalance the trie */	rcu_assign_pointer(t->trie, trie_rebalance(t, tp));done:	t->revision++;err:	return fa_head;}/* * Caller must hold RTNL. */static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg){	struct trie *t = (struct trie *) tb->tb_data;	struct fib_alias *fa, *new_fa;	struct list_head *fa_head = NULL;	struct fib_info *fi;	int plen = cfg->fc_dst_len;	u8 tos = cfg->fc_tos;	u32 key, mask;	int err;	struct leaf *l;	if (plen > 32)		return -EINVAL;	key = ntohl(cfg->fc_dst);	pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);	mask = ntohl(inet_make_mask(plen));	if (key & ~mask)		return -EINVAL;	key = key & mask;	fi = fib_create_info(cfg);	if (IS_ERR(fi)) {		err = PTR_ERR(fi);		goto err;	}	l = fib_find_node(t, key);	fa = NULL;	if (l) {		fa_head = get_fa_head(l, plen);		fa = fib_find_alias(fa_head, tos, fi->fib_priority);	}	/* Now fa, if non-NULL, points to the first fib alias	 * with the same keys [prefix,tos,priority], if such key already	 * exists or to the node before which we will insert new one.	 *	 * If fa is NULL, we will need to allocate a new one and	 * insert to the head of f.	 *	 * If f is NULL, no fib node matched the destination key	 * and we need to allocate a new one of those as well.	 */	if (fa && fa->fa_info->fib_priority == fi->fib_priority) {		struct fib_alias *fa_orig;		err = -EEXIST;		if (cfg->fc_nlflags & NLM_F_EXCL)			goto out;		if (cfg->fc_nlflags & NLM_F_REPLACE) {			struct fib_info *fi_drop;			u8 state;			if (fi->fib_treeref > 1)				goto out;			err = -ENOBUFS;			new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);			if (new_fa == NULL)				goto out;			fi_drop = fa->fa_info;			new_fa->fa_tos = fa->fa_tos;			new_fa->fa_info = fi;			new_fa->fa_type = cfg->fc_type;			new_fa->fa_scope = cfg->fc_scope;			state = fa->fa_state;			new_fa->fa_state &= ~FA_S_ACCESSED;			list_replace_rcu(&fa->fa_list, &new_fa->fa_list);			alias_free_mem_rcu(fa);			fib_release_info(fi_drop);			if (state & FA_S_ACCESSED)				rt_cache_flush(-1);			rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,				tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);			goto succeeded;		}		/* Error if we find a perfect match which		 * uses the same scope, type, and nexthop		 * information.		 */		fa_orig = fa;		list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {			if (fa->fa_tos != tos)				break;			if (fa->fa_info->fib_priority != fi->fib_priority)				break;			if (fa->fa_type == cfg->fc_type &&			    fa->fa_scope == cfg->fc_scope &&			    fa->fa_info == fi) {				goto out;			}		}		if (!(cfg->fc_nlflags & NLM_F_APPEND))			fa = fa_orig;	}	err = -ENOENT;	if (!(cfg->fc_nlflags & NLM_F_CREATE))		goto out;

⌨️ 快捷键说明

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