]> git.ipfire.org Git - location/libloc.git/commitdiff
network-list: Rewrite summarize algorithm
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 6 Mar 2022 15:06:17 +0000 (15:06 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 6 Mar 2022 15:06:17 +0000 (15:06 +0000)
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: Michael Tremer <michael.tremer@ipfire.org>
src/libloc/private.h
src/network-list.c

index 6b43990a58cb73c9eafb8a29a761a7390103e867..3b8782a1f592708c20f08199ba75cdc91221a8af 100644 (file)
@@ -130,6 +130,24 @@ static inline struct in6_addr loc_address_or(
        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) {
        char buffer_hex[16 * 3 + 6];
        char buffer_ascii[17];
index 58aa11e100a0b78b654b30df0b858511448228bf..61b36de84d29eaf601c157e08a8b2b9cd0a6e19e 100644 (file)
@@ -324,42 +324,46 @@ int loc_network_list_summarize(struct loc_ctx* ctx,
        }
 
        struct loc_network* network = NULL;
-
        struct in6_addr start = *first;
-       const struct in6_addr* end = NULL;
 
        while (in6_addr_cmp(&start, last) <= 0) {
-               // Guess the prefix
-               int prefix = 128 - loc_address_count_trailing_zero_bits(&start);
+               // Find the number of trailing zeroes of the start address
+               int bits1 = loc_address_count_trailing_zero_bits(&start);
 
-               while (1) {
-                       // Create a new network object
-                       r = loc_network_new(ctx, &network, &start, prefix);
-                       if (r)
-                               return r;
+               // 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);
 
-                       // Is this network within bounds?
-                       end = loc_network_get_last_address(network);
-                       if (in6_addr_cmp(last, end) <= 0)
-                               break;
+               // How many bits do we need to represent this address?
+               int bits2 = loc_address_bit_length(&num) - 1;
 
-                       // Drop network and decrease prefix
-                       loc_network_unref(network);
-                       prefix--;
+               // Select the smaller one
+               int bits = (bits1 > bits2) ? bits2 : bits1;
+
+               // 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);
                if (r) {
                        loc_network_unref(network);
                        return r;
                }
 
-               // Reset addr to the next start address
-               start = address_increment(end);
-
-               // Cleanup
-               loc_network_unref(network);
+               // The next network starts right after this one
+               start = *loc_network_get_last_address(network);
+               start = address_increment(&start);
        }
 
        return 0;