diff --git a/filter/trie.c b/filter/trie.c index 565ae82f..6477fbbf 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -277,8 +277,21 @@ trie_node_format(struct f_trie_node *t, buffer *buf) if (t == NULL) return; - if (ipa_nonzero(t->accept)) - buffer_print(buf, "%I/%d{%I}, ", t->addr, t->plen, t->accept); + ip_addr amask = t->accept; + while (ipa_nonzero(amask)) + { + int top, bottom; + ip_addr cmask = ipa_bitrange(amask, &top, &bottom); + + if ((t->plen == top) && (t->plen == bottom-1)) + buffer_print(buf, "%I/%d, ", t->addr, t->plen); + else if ((t->plen == top) && (bottom-1 == MAX_PREFIX_LENGTH)) + buffer_print(buf, "%I/%d+, ", t->addr, t->plen); + else + buffer_print(buf, "%I/%d{%d,%d}, ", t->addr, t->plen, top, bottom-1); + + amask = ipa_xor(amask, cmask); + } trie_node_format(t->c[0], buf); trie_node_format(t->c[1], buf); diff --git a/lib/bitops.c b/lib/bitops.c index 81586e87..9e05be57 100644 --- a/lib/bitops.c +++ b/lib/bitops.c @@ -68,3 +68,27 @@ u32_log2(u32 v) return r; } +/** + * u32_bitrange - find a contiguos series of 1's. + * @v: number + * @tp: pointer to top index (first 1: <31,0>) + * @bp: pointer to bottom index (first 0: <30,-1>) + * + * This functions finds the most significant contiguous series of 1's and returns it. + * If the pointers are set, the indices are also written there. + */ +u32 +u32_bitrange(u32 v, int *tp, int *bp) +{ + /* Example: 0x07ffe030 */ + int ti = u32_log2(v); /* Get first 1's index: 26 */ + u32 t = (1 << (ti + 1)) - 1; /* Get 1's mask: 0x07ffffff */ + u32 r = t ^ v; /* Unmask the 1's: 0x00001fcf */ + int bi = (v & (v+1)) ? (int)u32_log2(r) : -1; /* Get first 1's index: 12 */ + u32 b = (1 << (bi + 1)) - 1; /* Get the mask: 0x00001fff */ + if (tp) + *tp = ti; + if (bp) + *bp = bi; + return t ^ b; /* Return the bitrange: 0x07ffe000 */ +} diff --git a/lib/bitops.h b/lib/bitops.h index ce13732a..ae763289 100644 --- a/lib/bitops.h +++ b/lib/bitops.h @@ -22,6 +22,7 @@ u32 u32_mkmask(uint n); int u32_masklen(u32 x); u32 u32_log2(u32 v); +u32 u32_bitrange(u32 v, int *top, int *bottom); static inline u32 u32_hash(u32 v) { return v * 2902958171u; } diff --git a/lib/ip.h b/lib/ip.h index d876a707..aac55572 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -326,6 +326,15 @@ static inline ip4_addr ip4_mkmask(uint n) static inline int ip4_masklen(ip4_addr a) { return u32_masklen(_I(a)); } +static inline ip4_addr ip4_bitrange(ip4_addr a, int *tp, int *bp) +{ + int t, b; + a = u32_bitrange(a, &t, &b); + if (tp) *tp = 32-t; + if (bp) *bp = 32-b; + return a; +} + ip6_addr ip6_mkmask(uint n); int ip6_masklen(ip6_addr *a); @@ -373,6 +382,7 @@ ip4_addr ip4_class_mask(ip4_addr ad); #else #define ipa_mkmask(x) ip4_mkmask(x) #define ipa_masklen(x) ip4_masklen(x) +#define ipa_bitrange(x,tp,bp) ip4_bitrange(x,tp,bp) #define ipa_pxlen(x,y) ip4_pxlen(x,y) #define ipa_getbit(x,n) ip4_getbit(x,n) #define ipa_opposite_m1(x) ip4_opposite_m1(x)