summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/trie.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/filter/trie.c b/filter/trie.c
index 66b56297..50d349fe 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -373,9 +373,23 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
switch (net->type)
{
- case NET_IP4: px = ipt_from_ip4(net4_prefix(net)); v4 = 1; break;
- case NET_IP6: px = ipa_from_ip6(net6_prefix(net)); v4 = 0; break;
- default: bug("invalid type");
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ px = ipt_from_ip4(net4_prefix(net));
+ v4 = 1;
+ break;
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ case NET_IP6_SADR:
+ px = ipa_from_ip6(net6_prefix(net));
+ v4 = 0;
+ break;
+
+ default:
+ bug("invalid type");
}
if (t->ipv4 != v4)
@@ -562,7 +576,9 @@ trie_match_net(const struct f_trie *t, const net_addr *n)
* can be used to enumerate all matching prefixes for the network @net using
* function trie_match_next_longest_ip4() or macro TRIE_WALK_TO_ROOT_IP4().
*
- * This function assumes IPv4 trie, there is also an IPv6 variant.
+ * This function assumes IPv4 trie, there is also an IPv6 variant. The @net
+ * argument is typed as net_addr_ip4, but would accept any IPv4-based net_addr,
+ * like net4_prefix(). Anyway, returned @dst is always net_addr_ip4.
*
* Result: 1 if a matching prefix was found, 0 if not.
*/
@@ -571,6 +587,9 @@ trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr
{
ASSERT(t->ipv4);
+ const ip4_addr prefix = net->prefix;
+ const int pxlen = net->pxlen;
+
const struct f_trie_node4 *n = &t->root.v4;
int len = 0;
@@ -580,13 +599,13 @@ trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr
while (n)
{
/* We are out of path */
- if (!ip4_prefix_equal(net->prefix, n->addr, MIN(net->pxlen, n->plen)))
+ if (!ip4_prefix_equal(prefix, n->addr, MIN(pxlen, n->plen)))
goto done;
/* Check accept mask */
for (; len < n->plen; len++)
{
- if (len > net->pxlen)
+ if (len > pxlen)
goto done;
if (ip4_getbit(n->accept, len - 1))
@@ -607,9 +626,9 @@ trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr
}
/* Check local mask */
- for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip4_getbit(net->prefix, len), len++)
+ for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip4_getbit(prefix, len), len++)
{
- if (len > net->pxlen)
+ if (len > pxlen)
goto done;
if (n->local & (1u << pos))
@@ -621,16 +640,14 @@ trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr
}
/* Choose child */
- n = n->c[ip4_getbits(net->prefix, n->plen, TRIE_STEP)];
+ n = n->c[ip4_getbits(prefix, n->plen, TRIE_STEP)];
}
done:
if (last < 0)
return 0;
- net_copy_ip4(dst, net);
- dst->prefix = ip4_and(dst->prefix, ip4_mkmask(last));
- dst->pxlen = last;
+ *dst = NET_ADDR_IP4(ip4_and(prefix, ip4_mkmask(last)), last);
if (found0)
*found0 = found;
@@ -653,7 +670,9 @@ done:
* can be used to enumerate all matching prefixes for the network @net using
* function trie_match_next_longest_ip6() or macro TRIE_WALK_TO_ROOT_IP6().
*
- * This function assumes IPv6 trie, there is also an IPv4 variant.
+ * This function assumes IPv6 trie, there is also an IPv4 variant. The @net
+ * argument is typed as net_addr_ip6, but would accept any IPv6-based net_addr,
+ * like net6_prefix(). Anyway, returned @dst is always net_addr_ip6.
*
* Result: 1 if a matching prefix was found, 0 if not.
*/
@@ -662,6 +681,9 @@ trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr
{
ASSERT(!t->ipv4);
+ const ip6_addr prefix = net->prefix;
+ const int pxlen = net->pxlen;
+
const struct f_trie_node6 *n = &t->root.v6;
int len = 0;
@@ -671,13 +693,13 @@ trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr
while (n)
{
/* We are out of path */
- if (!ip6_prefix_equal(net->prefix, n->addr, MIN(net->pxlen, n->plen)))
+ if (!ip6_prefix_equal(prefix, n->addr, MIN(pxlen, n->plen)))
goto done;
/* Check accept mask */
for (; len < n->plen; len++)
{
- if (len > net->pxlen)
+ if (len > pxlen)
goto done;
if (ip6_getbit(n->accept, len - 1))
@@ -698,9 +720,9 @@ trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr
}
/* Check local mask */
- for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip6_getbit(net->prefix, len), len++)
+ for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip6_getbit(prefix, len), len++)
{
- if (len > net->pxlen)
+ if (len > pxlen)
goto done;
if (n->local & (1u << pos))
@@ -712,16 +734,14 @@ trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr
}
/* Choose child */
- n = n->c[ip6_getbits(net->prefix, n->plen, TRIE_STEP)];
+ n = n->c[ip6_getbits(prefix, n->plen, TRIE_STEP)];
}
done:
if (last < 0)
return 0;
- net_copy_ip6(dst, net);
- dst->prefix = ip6_and(dst->prefix, ip6_mkmask(last));
- dst->pxlen = last;
+ *dst = NET_ADDR_IP6(ip6_and(prefix, ip6_mkmask(last)), last);
if (found0)
*found0 = found;