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);
while (1) { // Subtract the start address from the last address and add one
// Create a new network object // (i.e. how many addresses are in this network?)
r = loc_network_new(ctx, &network, &start, prefix); struct in6_addr num = loc_address_sub(last, &start);
if (r) num = address_increment(&num);
return r;
// Is this network within bounds? // How many bits do we need to represent this address?
end = loc_network_get_last_address(network); int bits2 = loc_address_bit_length(&num) - 1;
if (in6_addr_cmp(last, end) <= 0)
break;
// Drop network and decrease prefix // Select the smaller one
loc_network_unref(network); int bits = (bits1 > bits2) ? bits2 : bits1;
prefix--;
// Create a network
r = loc_network_new(ctx, &network, &start, 128 - bits);
if (r)
return r;
#ifdef ENABLE_DEBUG
char* n = loc_network_str(network);
if (n) {
DEBUG(ctx, "Found network %s\n", n);
free(n);
} }
#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