/** * trie_match * @t: trie * @px: prefix address * @plen: prefix length * * Tries to find a matching prefix pattern in the trie such that * prefix @px/@plen matches that prefix pattern. Returns 1 if there * is such prefix pattern in the trie. */ int trie_match_prefix(struct f_trie *t, ip_addr px, int plen) { ip_addr pmask = ipa_mkmask(plen); ip_addr paddr = ipa_and(px, pmask); if (plen == 0) return t->zero; int plentest = plen - 1; struct f_trie_node *n = &t->root; while(n) { ip_addr cmask = ipa_and(n->mask, pmask); /* We are out of path */ if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask))) return 0; /* Check accept mask */ if (ipa_getbit(n->accept, plentest)) return 1; /* We finished trie walk and still no match */ if (plen <= n->plen) return 0; /* Choose children */ n = n->c[(ipa_getbit(paddr, n->plen)) ? 1 : 0]; } return 0; }
/* Compare nexthops during merge. We need to maintain nhs sorted to eliminate duplicities */ static int cmp_nhs(struct mpnh *s1, struct mpnh *s2) { int r; if (!s1) return 1; if (!s2) return -1; r = ((int) s2->weight) - ((int) s1->weight); if (r) return r; r = ipa_compare(s1->gw, s2->gw); if (r) return r; return ((int) s1->iface->index) - ((int) s2->iface->index); }
void trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h) { if (l == 0) t->zero = 1; else l--; if (h < plen) plen = h; ip_addr amask = ipa_xor(ipa_mkmask(l), ipa_mkmask(h)); ip_addr pmask = ipa_mkmask(plen); ip_addr paddr = ipa_and(px, pmask); struct f_trie_node *o = NULL; struct f_trie_node *n = &t->root; while(n) { ip_addr cmask = ipa_and(n->mask, pmask); if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask))) { /* We are out of path - we have to add branching node 'b' between node 'o' and node 'n', and attach new node 'a' as the other child of 'b'. */ int blen = ipa_pxlen(paddr, n->addr); ip_addr bmask = ipa_mkmask(blen); ip_addr baddr = ipa_and(px, bmask); /* Merge accept masks from children to get accept mask for node 'b' */ ip_addr baccm = ipa_and(ipa_or(amask, n->accept), bmask); struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask); struct f_trie_node *b = new_node(t, blen, baddr, bmask, baccm); attach_node(o, b); attach_node(b, n); attach_node(b, a); return; } if (plen < n->plen) { /* We add new node 'a' between node 'o' and node 'n' */ amask = ipa_or(amask, ipa_and(n->accept, pmask)); struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask); attach_node(o, a); attach_node(a, n); return; } if (plen == n->plen) { /* We already found added node in trie. Just update accept mask */ n->accept = ipa_or(n->accept, amask); return; } /* Update accept mask part M2 and go deeper */ n->accept = ipa_or(n->accept, ipa_and(amask, n->mask)); /* n->plen < plen and plen <= 32 (128) */ o = n; n = n->c[ipa_getbit(paddr, n->plen) ? 1 : 0]; } /* We add new tail node 'a' after node 'o' */ struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask); attach_node(o, a); }