/* This provides us with the number of children in this node, in the case of a *leafthiswillreturn0meaningnoneofthechildrenareaccessible.
*/ staticinlineunsignedlong child_length(conststruct key_vector *tn)
{ return (1ul << tn->bits) & ~(1ul);
}
/* Check whether a tnode 'n' is "full", i.e. it is an internal node *andnobitsareskipped.Seediscussionindyntreepaperp.6
*/ staticinlineint tnode_full(struct key_vector *tn, struct key_vector *n)
{ return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
}
/* Add a child at position i overwriting the old value. *Updatethevalueoffull_childrenandempty_children.
*/ staticvoid put_child(struct key_vector *tn, unsignedlong i, struct key_vector *n)
{ struct key_vector *chi = get_child(tn, i); int isfull, wasfull;
BUG_ON(i >= child_length(tn));
/* update emptyChildren, overflow into fullChildren */ if (!n && chi)
empty_child_inc(tn); if (n && !chi)
empty_child_dec(tn);
/* update all of the child parent pointers */ for (i = child_length(tn); i;) { struct key_vector *inode = get_child(tn, --i);
if (!inode) continue;
/* Either update the children of a tnode that *alreadybelongstousorupdatethechild *topointtoourselves.
*/ if (node_parent(inode) == tn)
update_children(inode); else
node_set_parent(inode, tn);
}
}
/* prepare oldtnode to be freed */
tnode_free_init(oldtnode);
/* Assemble all of the pointers in our cluster, in this case that *representsallofthepointersoutofourallocatednodesthat *pointtoexistingtnodesandthelinksbetweenourallocated *nodes.
*/ for (i = child_length(oldtnode), m = 1u << tn->pos; i;) { struct key_vector *inode = get_child(oldtnode, --i); struct key_vector *node0, *node1; unsignedlong j, k;
/* An empty child */ if (!inode) continue;
/* A leaf or an internal node with skipped bits */ if (!tnode_full(oldtnode, inode)) {
put_child(tn, get_index(inode->key, tn), inode); continue;
}
/* drop the node in the old tnode free list */
tnode_free_append(oldtnode, inode);
/* An internal node with two children */ if (inode->bits == 1) {
put_child(tn, 2 * i + 1, get_child(inode, 1));
put_child(tn, 2 * i, get_child(inode, 0)); continue;
}
/* We will replace this node 'inode' with two new *ones,'node0'and'node1',eachwithhalfofthe *originalchildren.Thetwonewnodeswillhave *apositiononebitfurtherdownthekeyandthis *meansthatthe"significant"partoftheirkeys *(seethediscussionnearthetopofthisfile) *willdifferbyonebit,whichwillbe"0"in *node0'skeyand"1"innode1'skey.Sinceweare *movingthekeypositionbyonestep,thebitthat *wearemovingawayfrom-thebitatposition *(tn->pos)-istheonethatwilldifferbetween *node0andnode1.So...wesynthesizethatbitinthe *twonewkeys.
*/
node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); if (!node1) goto nomem;
node0 = tnode_new(inode->key, inode->pos, inode->bits - 1);
tnode_free_append(tn, node1); if (!node0) goto nomem;
tnode_free_append(tn, node0);
/* populate child pointers in new nodes */ for (k = child_length(inode), j = k / 2; j;) {
put_child(node1, --j, get_child(inode, --k));
put_child(node0, j, get_child(inode, j));
put_child(node1, --j, get_child(inode, --k));
put_child(node0, j, get_child(inode, j));
}
/* link new nodes to parent */
NODE_INIT_PARENT(node1, tn);
NODE_INIT_PARENT(node0, tn);
/* link parent to nodes */
put_child(tn, 2 * i + 1, node1);
put_child(tn, 2 * i, node0);
}
/* setup the parent pointers into and out of this node */ return replace(t, oldtnode, tn);
nomem: /* all pointers should be clean so we are done */
tnode_free(tn);
notnode: return NULL;
}
/* prepare oldtnode to be freed */
tnode_free_init(oldtnode);
/* Assemble all of the pointers in our cluster, in this case that *representsallofthepointersoutofourallocatednodesthat *pointtoexistingtnodesandthelinksbetweenourallocated *nodes.
*/ for (i = child_length(oldtnode); i;) { struct key_vector *node1 = get_child(oldtnode, --i); struct key_vector *node0 = get_child(oldtnode, --i); struct key_vector *inode;
/* At least one of the children is empty */ if (!node1 || !node0) {
put_child(tn, i / 2, node1 ? : node0); continue;
}
/* Two nonempty children */
inode = tnode_new(node0->key, oldtnode->pos, 1); if (!inode) goto nomem;
tnode_free_append(tn, inode);
/* initialize pointers out of node */
put_child(inode, 1, node1);
put_child(inode, 0, node0);
NODE_INIT_PARENT(inode, tn);
/* link parent to node */
put_child(tn, i / 2, inode);
}
/* setup the parent pointers into and out of this node */ return replace(t, oldtnode, tn);
nomem: /* all pointers should be clean so we are done */
tnode_free(tn);
notnode: return NULL;
}
/* scan the tnode looking for that one child that might still exist */ for (n = NULL, i = child_length(oldtnode); !n && i;)
n = get_child(oldtnode, --i);
/* only vector 0 can have a suffix length greater than or equal to *tn->pos+tn->bits,thesecondhighestnodewillhaveasuffix *lengthatmostoftn->pos+tn->bits-1
*/
slen_max = min_t(unsignedchar, tn->pos + tn->bits - 1, tn->slen);
/* search though the list of children looking for nodes that might *haveasuffixgreaterthantheonewecurrentlyhave.Thisis *whywestartwithastrideof2sinceastrideof1would *representthenodeswithsuffixlengthequaltotn->pos
*/ for (i = 0, stride = 0x2ul ; i < child_length(tn); i += stride) { struct key_vector *n = get_child(tn, i);
if (!n || (n->slen <= slen)) continue;
/* update stride and slen based on new value */
stride <<= (n->slen - slen);
slen = n->slen;
i &= ~(stride - 1);
/* stop searching if we have hit the maximum possible value */ if (slen >= slen_max) break;
}
/* track the tnode via the pointer from the parent instead of *doingitourselves.ThiswaywecanletRCUfullydoits *thingwithoutusinterfering
*/
BUG_ON(tn != get_child(tp, cindex));
/* Double as long as the resulting node has a number of *nonemptynodesthatareabovethethreshold.
*/ while (should_inflate(tp, tn) && max_work) {
tp = inflate(t, tn); if (!tp) { #ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(stats->resize_node_skipped); #endif break;
}
max_work--;
tn = get_child(tp, cindex);
}
/* update parent in case inflate failed */
tp = node_parent(tn);
/* Return if at least one inflate is run */ if (max_work != MAX_WORK) return tp;
/* Halve as long as the number of empty children in this *nodeisabovethreshold.
*/ while (should_halve(tp, tn) && max_work) {
tp = halve(t, tn); if (!tp) { #ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(stats->resize_node_skipped); #endif break;
}
max_work--;
tn = get_child(tp, cindex);
}
/* Only one child remains */ if (should_collapse(tn)) return collapse(t, tn);
/* update parent in case halve failed */ return node_parent(tn);
}
/* rcu_read_lock needs to be hold by caller from readside */ staticstruct key_vector *fib_find_node(struct trie *t, struct key_vector **tp, u32 key)
{ struct key_vector *pn, *n = t->kv; unsignedlong index = 0;
do {
pn = n;
n = get_child_rcu(n, index);
if (!n) break;
index = get_cindex(key, n);
/* This bit of code is a bit tricky but it combines multiple *checksintoasinglecheck.Theprefixconsistsofthe *prefixpluszerosforthebitsinthecindex.Theindex *isthedifferencebetweenthekeyandthisvalue.From *thiswecanactuallyderiveseveralpiecesofdata. *if(index>=(1ul<<bits)) *wehaveamismatchinskipbitsandfailed *else *weknowthevalueiscindex * *Thischeckissafeevenifbits==KEYLENGTHduetothe *factthatwecanonlyallocateanodewith32bitsifa *longisgreaterthan32bits.
*/ if (index >= (1ul << n->bits)) {
n = NULL; break;
}
/* keep searching until we find a perfect match leaf or NULL */
} while (IS_TNODE(n));
*tp = pn;
return n;
}
/* Return the first fib alias matching DSCP with *prioritylessthanorequaltoPRIO. *If'find_first'isset,returnthefirstmatching *fibalias,regardlessofDSCPandpriority.
*/ staticstruct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen,
dscp_t dscp, u32 prio, u32 tb_id, bool find_first)
{ struct fib_alias *fa;
if (!fah) return NULL;
hlist_for_each_entry(fa, fah, fa_list) { /* Avoid Sparse warning when using dscp_t in inequalities */
u8 __fa_dscp = inet_dscp_to_dsfield(fa->fa_dscp);
u8 __dscp = inet_dscp_to_dsfield(dscp);
if (fa->fa_slen < slen) continue; if (fa->fa_slen != slen) break; if (fa->tb_id > tb_id) continue; if (fa->tb_id != tb_id) break; if (find_first) return fa; if (__fa_dscp > __dscp) continue; if (fa->fa_info->fib_priority >= prio || __fa_dscp < __dscp) return fa;
}
void fib_alias_hw_flags_set(struct net *net, conststruct fib_rt_info *fri)
{
u8 fib_notify_on_flag_change; struct fib_alias *fa_match; struct sk_buff *skb; int err;
rcu_read_lock();
fa_match = fib_find_matching_alias(net, fri); if (!fa_match) goto out;
/* These are paired with the WRITE_ONCE() happening in this function. *ThereasonisthatweareonlyprotectedbyRCUatthispoint.
*/ if (READ_ONCE(fa_match->offload) == fri->offload &&
READ_ONCE(fa_match->trap) == fri->trap &&
READ_ONCE(fa_match->offload_failed) == fri->offload_failed) goto out;
/* 2 means send notifications only if offload_failed was changed. */ if (fib_notify_on_flag_change == 2 &&
READ_ONCE(fa_match->offload_failed) == fri->offload_failed) goto out;
/* retrieve child from parent node */
n = get_child(tp, get_index(key, tp));
/* Case 2: n is a LEAF or a TNODE and the key doesn't match. * *Addanewtnodehere *firsttnodeneedsomespecialhandling *leavesusinpositionforhandlingascase3
*/ if (n) { struct key_vector *tn;
/* initialize routes out of node */
NODE_INIT_PARENT(tn, tp);
put_child(tn, get_index(key, tn) ^ 1, n);
/* start adding routes into the node */
put_child_root(tp, key, tn);
node_set_parent(n, tn);
/* parent now has a NULL spot where the leaf can go */
tp = tn;
}
/* Case 3: n is NULL, and will just insert a new leaf */
node_push_suffix(tp, new->fa_slen);
NODE_INIT_PARENT(l, tp);
put_child_root(tp, key, l);
trie_rebalance(t, tp);
hlist_for_each_entry(last, &l->leaf, fa_list) { if (new->fa_slen < last->fa_slen) break; if ((new->fa_slen == last->fa_slen) &&
(new->tb_id > last->tb_id)) break;
fa = last;
}
if (fa)
hlist_add_behind_rcu(&new->fa_list, &fa->fa_list); else
hlist_add_head_rcu(&new->fa_list, &l->leaf);
}
/* if we added to the tail node then we need to update slen */ if (l->slen < new->fa_slen) {
l->slen = new->fa_slen;
node_push_suffix(tp, new->fa_slen);
}
fi = fib_create_info(cfg, extack); if (IS_ERR(fi)) {
err = PTR_ERR(fi); goto err;
}
dscp = cfg->fc_dscp;
l = fib_find_node(t, &tp, key);
fa = l ? fib_find_alias(&l->leaf, slen, dscp, fi->fib_priority,
tb->tb_id, false) : NULL;
/* Now fa, if non-NULL, points to the first fib alias *withthesamekeys[prefix,dscp,priority],ifsuchkeyalready *existsortothenodebeforewhichwewillinsertnewone. * *IffaisNULL,wewillneedtoallocateanewoneand *inserttothetailofthesectionmatchingthesuffixlength *ofthenewalias.
*/
/* Insert new entry to the list. */
err = fib_insert_alias(t, tp, l, new_fa, fa, key); if (err) goto out_free_new_fa;
/* The alias was already inserted, so the node must exist. */
l = l ? l : fib_find_node(t, &tp, key); if (WARN_ON_ONCE(!l)) {
err = -ENOENT; goto out_free_new_fa;
}
/* Step 1: Travel to the longest prefix match in the trie */ for (;;) {
index = get_cindex(key, n);
/* This bit of code is a bit tricky but it combines multiple *checksintoasinglecheck.Theprefixconsistsofthe *prefixpluszerosforthe"bits"intheprefix.Theindex *isthedifferencebetweenthekeyandthisvalue.From *thiswecanactuallyderiveseveralpiecesofdata. *if(index>=(1ul<<bits)) *wehaveamismatchinskipbitsandfailed *else *weknowthevalueiscindex * *Thischeckissafeevenifbits==KEYLENGTHduetothe *factthatwecanonlyallocateanodewith32bitsifa *longisgreaterthan32bits.
*/ if (index >= (1ul << n->bits)) break;
/* we have found a leaf. Prefixes have already been compared */ if (IS_LEAF(n)) goto found;
/* only record pn and cindex if we are going to be chopping *bitslater.Otherwisewearejustwastingcycles.
*/ if (n->slen > n->pos) {
pn = n;
cindex = index;
}
n = get_child_rcu(n, index); if (unlikely(!n)) goto backtrace;
}
/* Step 2: Sort out leaves and begin backtracing for longest prefix */ for (;;) { /* record the pointer where our next node pointer is stored */ struct key_vector __rcu **cptr = n->tnode;
/* This test verifies that none of the bits that differ *betweenthekeyandtheprefixexistintheregionof *thelsbandhigherintheprefix.
*/ if (unlikely(prefix_mismatch(key, n)) || (n->slen == n->pos)) goto backtrace;
/* exit out and process leaf */ if (unlikely(IS_LEAF(n))) break;
/* Don't bother recording parent info. Since we are in *prefixmatchmodewewillhavetocomebacktowherever *westartedthistraversalanyway
*/
while ((n = rcu_dereference(*cptr)) == NULL) {
backtrace: #ifdef CONFIG_IP_FIB_TRIE_STATS if (!n)
this_cpu_inc(stats->null_node_hit); #endif /* If we are at cindex 0 there are no more bits for *ustostripatthislevelsowemustascendback *uponeleveltoseeifthereareanymorebitsto *bestrippedthere.
*/ while (!cindex) {
t_key pkey = pn->key;
/* If we don't have a parent then there is *nothingforustodoaswedonothaveany *furthernodestoparse.
*/ if (IS_TRIE(pn)) {
trace_fib_table_lookup(tb->tb_id, flp,
NULL, -EAGAIN); return -EAGAIN;
} #ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(stats->backtrack); #endif /* Get Child's index */
pn = node_parent_rcu(pn);
cindex = get_index(pkey, pn);
}
/* strip the least significant bit from the cindex */
cindex &= cindex - 1;
/* grab pointer for next child node */
cptr = &pn->tnode[cindex];
}
}
found: /* this line carries forward the xor from earlier in the function */
index = key ^ n->key;
/* Step 3: Process the leaf, if that fails fall back to backtracing */
hlist_for_each_entry_rcu(fa, &n->leaf, fa_list) { struct fib_info *fi = fa->fa_info; struct fib_nh_common *nhc; int nhsel, err;
if ((BITS_PER_LONG > KEYLENGTH) || (fa->fa_slen < KEYLENGTH)) { if (index >= (1ul << fa->fa_slen)) continue;
} if (fa->fa_dscp && !fib_dscp_masked_match(fa->fa_dscp, flp)) continue; /* Paired with WRITE_ONCE() in fib_release_info() */ if (READ_ONCE(fi->fib_dead)) continue; if (fa->fa_info->fib_scope < flp->flowi4_scope) continue;
fib_alias_accessed(fa);
err = fib_props[fa->fa_type].error; if (unlikely(err < 0)) {
out_reject: #ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(stats->semantic_match_passed); #endif
trace_fib_table_lookup(tb->tb_id, flp, NULL, err); return err;
} if (fi->fib_flags & RTNH_F_DEAD) continue;
if (unlikely(fi->nh)) { if (nexthop_is_blackhole(fi->nh)) {
err = fib_props[RTN_BLACKHOLE].error; goto out_reject;
}
staticvoid fib_remove_alias(struct trie *t, struct key_vector *tp, struct key_vector *l, struct fib_alias *old)
{ /* record the location of the previous list_info entry */ struct hlist_node **pprev = old->fa_list.pprev; struct fib_alias *fa = hlist_entry(pprev, typeof(*fa), fa_list.next);
/* remove the fib_alias from the list */
hlist_del_rcu(&old->fa_list);
/* if we emptied the list this leaf will be freed and we can sort *outparentsuffixlengthsasapartoftrie_rebalance
*/ if (hlist_empty(&l->leaf)) { if (tp->slen == l->slen)
node_pull_suffix(tp, tp->pos);
put_child_root(tp, l->key, NULL);
node_free(l);
trie_rebalance(t, tp); return;
}
/* only access fa if it is pointing at the last valid hlist_node */ if (*pprev) return;
/* update the trie with the latest suffix length */
l->slen = fa->fa_slen;
node_pull_suffix(tp, fa->fa_slen);
}
/* Scan for the next leaf starting at the provided key value */ staticstruct key_vector *leaf_walk_rcu(struct key_vector **tn, t_key key)
{ struct key_vector *pn, *n = *tn; unsignedlong cindex;
/* this loop is meant to try and find the key in the trie */ do { /* record parent and next child index */
pn = n;
cindex = (key > pn->key) ? get_index(key, pn) : 0;
if (cindex >> pn->bits) break;
/* descend into the next child */
n = get_child_rcu(pn, cindex++); if (!n) break;
/* guarantee forward progress on the keys */ if (IS_LEAF(n) && (n->key >= key)) goto found;
} while (IS_TNODE(n));
/* this loop will search for the next leaf with a greater key */ while (!IS_TRIE(pn)) { /* if we exhausted the parent node we will need to climb */ if (cindex >= (1ul << pn->bits)) {
t_key pkey = pn->key;
/* grab the next available node */
n = get_child(pn, cindex); if (!n) continue;
if (IS_TNODE(n)) { /* record pn and cindex for leaf walking */
pn = n;
cindex = 1ul << n->bits;
continue;
}
hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { /* if alias was cloned to local then we just *needtoremovethelocalcopyfrommain
*/ if (tb->tb_id != fa->tb_id) {
hlist_del_rcu(&fa->fa_list);
alias_free_mem_rcu(fa); continue;
}
/* record local slen */
slen = fa->fa_slen;
}
/* update leaf slen */
n->slen = slen;
if (hlist_empty(&n->leaf)) {
put_child_root(pn, n->key, NULL);
node_free(n);
}
}
}
/* Caller must hold RTNL. */ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
{ struct trie *t = (struct trie *)tb->tb_data; struct nl_info info = { .nl_net = net }; struct key_vector *pn = t->kv; unsignedlong cindex = 1; struct hlist_node *tmp; struct fib_alias *fa; int found = 0;
/* walk trie in reverse order */ for (;;) { unsignedchar slen = 0; struct key_vector *n;
if (!(cindex--)) {
t_key pkey = pn->key;
/* cannot resize the trie vector */ if (IS_TRIE(pn)) break;
/* update the suffix to address pulled leaves */ if (pn->slen > pn->pos)
update_suffix(pn);
/* Do not flush error routes if network namespace is *notbeingdismantled
*/ if (!flush_all && fib_props[fa->fa_type].error) {
slen = fa->fa_slen; continue;
}
int __net_init fib_proc_init(struct net *net)
{ if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, sizeof(struct fib_trie_iter))) goto out1;
if (!proc_create_net_single("fib_triestat", 0444, net->proc_net,
fib_triestat_seq_show, NULL)) goto out2;
if (!proc_create_net("route", 0444, net->proc_net, &fib_route_seq_ops, sizeof(struct fib_route_iter))) goto out3;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.173Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.