Commit d701dcfd authored by Michael Tremer's avatar Michael Tremer

network-list: Rewrite summarize algorithm

The former algorithm did a lot of trial and error which is slow and
probably returned wrong results.

This one determines the correct prefix size quickly.
Signed-off-by: default avatarMichael Tremer <michael.tremer@ipfire.org>
parent 7f834833
...@@ -130,6 +130,24 @@ static inline struct in6_addr loc_address_or( ...@@ -130,6 +130,24 @@ static inline struct in6_addr loc_address_or(
return a; return a;
} }
static inline struct in6_addr loc_address_sub(
const struct in6_addr* address1, const struct in6_addr* address2) {
struct in6_addr a;
int remainder = 0;
for (int octet = 15; octet >= 0; octet--) {
int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
// Store remainder for the next iteration
remainder = (x >> 8);
a.s6_addr[octet] = x & 0xff;
}
return a;
}
static inline void hexdump(struct loc_ctx* ctx, const void* addr, size_t len) { static inline void hexdump(struct loc_ctx* ctx, const void* addr, size_t len) {
char buffer_hex[16 * 3 + 6]; char buffer_hex[16 * 3 + 6];
char buffer_ascii[17]; char buffer_ascii[17];
......
...@@ -324,42 +324,46 @@ int loc_network_list_summarize(struct loc_ctx* ctx, ...@@ -324,42 +324,46 @@ int loc_network_list_summarize(struct loc_ctx* ctx,
} }
struct loc_network* network = NULL; struct loc_network* network = NULL;
struct in6_addr start = *first; struct in6_addr start = *first;
const struct in6_addr* end = NULL;
while (in6_addr_cmp(&start, last) <= 0) { while (in6_addr_cmp(&start, last) <= 0) {
// Guess the prefix // Find the number of trailing zeroes of the start address
int prefix = 128 - loc_address_count_trailing_zero_bits(&start); int bits1 = loc_address_count_trailing_zero_bits(&start);
// Subtract the start address from the last address and add one
// (i.e. how many addresses are in this network?)
struct in6_addr num = loc_address_sub(last, &start);
num = address_increment(&num);
// How many bits do we need to represent this address?
int bits2 = loc_address_bit_length(&num) - 1;
while (1) { // Select the smaller one
// Create a new network object int bits = (bits1 > bits2) ? bits2 : bits1;
r = loc_network_new(ctx, &network, &start, prefix);
// Create a network
r = loc_network_new(ctx, &network, &start, 128 - bits);
if (r) if (r)
return r; return r;
// Is this network within bounds? #ifdef ENABLE_DEBUG
end = loc_network_get_last_address(network); char* n = loc_network_str(network);
if (in6_addr_cmp(last, end) <= 0) if (n) {
break; DEBUG(ctx, "Found network %s\n", n);
free(n);
// Drop network and decrease prefix
loc_network_unref(network);
prefix--;
} }
#endif
// Push it on the list // Push network on the list
r = loc_network_list_push(*list, network); r = loc_network_list_push(*list, network);
if (r) { if (r) {
loc_network_unref(network); loc_network_unref(network);
return r; return r;
} }
// Reset addr to the next start address // The next network starts right after this one
start = address_increment(end); start = *loc_network_get_last_address(network);
start = address_increment(&start);
// Cleanup
loc_network_unref(network);
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment