BBlack has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/84013


Change subject: Backport nlist.[ch] changes from gdnsd
......................................................................

Backport nlist.[ch] changes from gdnsd

This gives us the ability to normalize truly ugly lists
  of networks from the JSON input, instead of failing on
  things like duplicates, merge-generated duplicates, and conflicts.

Change-Id: Ib1e6d95ac7ad687933a3e65cdab45ea02ec9e303
---
M src/nlt/nlist.c
M src/nlt/nlist.h
M src/vnm.c
3 files changed, 31 insertions(+), 59 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/operations/software/varnish/libvmod-netmapper 
refs/changes/13/84013/1

diff --git a/src/nlt/nlist.c b/src/nlt/nlist.c
index d0c587d..0d34c7b 100644
--- a/src/nlt/nlist.c
+++ b/src/nlt/nlist.c
@@ -36,7 +36,7 @@
     net_t* nets;
     unsigned alloc;
     unsigned count;
-    bool finished;
+    bool normalized;
 };
 
 nlist_t* nlist_new(void) {
@@ -44,7 +44,7 @@
     nl->nets = malloc(sizeof(net_t) * NLIST_INITSIZE);
     nl->alloc = NLIST_INITSIZE;
     nl->count = 0;
-    nl->finished = false;
+    nl->normalized = false;
     return nl;
 }
 
@@ -96,25 +96,6 @@
     return rv;
 }
 
-// sort and check for dupes, true retval indicates failure due to dupes
-static bool nlist_normalize1(nlist_t* nl) {
-    assert(nl);
-
-    if(nl->count) {
-        qsort(nl->nets, nl->count, sizeof(net_t), net_sorter);
-
-        for(unsigned i = 0; i < (nl->count - 1); i++) {
-            net_t* net_a = &nl->nets[i];
-            net_t* net_b = &nl->nets[i + 1];
-            if(net_a->mask == net_b->mask && !memcmp(net_a->ipv6, net_b->ipv6, 
16)) {
-               return true;
-            }
-        }
-    }
-
-    return false;
-}
-
 static bool masked_net_eq(const uint8_t* v6a, const uint8_t* v6b, const 
unsigned mask) {
     assert(v6a); assert(v6b);
     assert(mask < 128U); // 2x128 would call here w/ 127...
@@ -146,34 +127,42 @@
     this_net->mask = mask;
     this_net->dclist = dclist;
 
-    // for raw input, just correct any netmask errors as we insert,
-    //   as these will screw up later sorting for normalize1
     return clear_mask_bits(this_net->ipv6, mask);
 }
 
-// merge adjacent nets with identical dclists recursively...
-static void nlist_normalize2(nlist_t* nl) {
+static bool net_eq(const net_t* na, const net_t* nb) {
+    assert(na); assert(nb);
+    return na->mask == nb->mask && !memcmp(na->ipv6, nb->ipv6, 16);
+}
+
+// normalize ugly random-ish lists
+static void nlist_normalize(nlist_t* nl, const bool post_merge) {
     assert(nl);
 
     if(nl->count) {
+        if(!post_merge)
+            qsort(nl->nets, nl->count, sizeof(net_t), net_sorter);
+
         unsigned idx = nl->count;
         unsigned newcount = nl->count;
         while(--idx > 0) {
             net_t* nb = &nl->nets[idx];
             net_t* na = &nl->nets[idx - 1];
-            if(mergeable_nets(na, nb)) {
-                // na should have the differential bit clear
-                //   thanks to pre-sorting, so just needs mask--
+            const bool ab_eq = net_eq(na, nb);
+            if(ab_eq || mergeable_nets(na, nb)) {
                 nb->mask = MASK_DELETED;
-                na->mask--;
+                if(!ab_eq)
+                    na->mask--;
                 newcount--;
                 unsigned upidx = idx + 1;
                 while(upidx < nl->count) {
                     net_t* nc = &nl->nets[upidx];
                     if(nc->mask != MASK_DELETED) {
-                        if(mergeable_nets(na, nc)) {
+                        const bool ac_eq = net_eq(na, nc);
+                        if(ac_eq || mergeable_nets(na, nc)) {
                             nc->mask = MASK_DELETED;
-                            na->mask--;
+                            if(!ac_eq)
+                                na->mask--;
                             newcount--;
                         }
                         else {
@@ -204,18 +193,14 @@
             nl->nets = realloc(nl->nets, sizeof(net_t) * nl->alloc);
         }
     }
+
+    nl->normalized = true;
 }
 
-bool nlist_finish(nlist_t* nl) {
+void nlist_finish(nlist_t* nl) {
     assert(nl);
-
-    bool rv = nlist_normalize1(nl);
-    if(!rv) {
-        nlist_normalize2(nl);
-        nl->finished = true;
-    }
-
-    return rv;
+    if(!nl->normalized)
+        nlist_normalize(nl, false);
 }
 
 static bool net_subnet_of(const net_t* sub, const net_t* super) {
@@ -295,15 +280,11 @@
     SETBIT_v6(tree_net.ipv6, tree_net.mask - 1);
     nxt_rec_dir(nl, nl_end, nt, tree_net, nt_idx, true);
 
-    // catch missed optimizations during final translation,
-    //   which should be on the default dclist zero
-    //   due to it being implicit for undefined nets in the list,
-    //   and thus not merged with true list entries...
+    // catch missed optimizations during final translation
     unsigned rv;
-    if((nt->store[nt_idx].zero == nt->store[nt_idx].one) && (nt_idx > 0)) {
-        assert(nt->store[nt_idx].zero == NN_SET_DCLIST(0));
+    if(nt->store[nt_idx].zero == nt->store[nt_idx].one && nt_idx > 0) {
         nt->count--; // delete the just-added node
-        rv = NN_SET_DCLIST(0); // retval is now a dclist rather than a node...
+        rv = nt->store[nt_idx].zero;
     }
     else {
         rv = nt_idx;
@@ -313,7 +294,7 @@
 
 ntree_t* nlist_xlate_tree(const nlist_t* nl) {
     assert(nl);
-    assert(nl->finished);
+    assert(nl->normalized);
 
     ntree_t* nt = ntree_new();
     const net_t* nlnet = &nl->nets[0];
@@ -345,4 +326,3 @@
 
     return nt;
 }
-
diff --git a/src/nlt/nlist.h b/src/nlt/nlist.h
index 0eaa1b3..1987e46 100644
--- a/src/nlt/nlist.h
+++ b/src/nlt/nlist.h
@@ -37,8 +37,7 @@
 bool nlist_append(nlist_t* nl, const uint8_t* ipv6, const unsigned mask, const 
unsigned dclist);
 
 // Call this when all nlist_append() are complete. 
-// true retval here indicates failure due to duplicate networks
-bool nlist_finish(nlist_t* nl);
+void nlist_finish(nlist_t* nl);
 
 // must pass through _finish() before xlate!
 ntree_t* nlist_xlate_tree(const nlist_t* nl_a);
diff --git a/src/vnm.c b/src/vnm.c
index eb94242..353fc89 100644
--- a/src/vnm.c
+++ b/src/vnm.c
@@ -229,14 +229,7 @@
     nlist_append(templist, start_siit, 96, NN_UNDEF);
     nlist_append(templist, start_6to4, 16, NN_UNDEF);
     nlist_append(templist, start_teredo, 32, NN_UNDEF);
-    if(nlist_finish(templist)) {
-        ERR("JSON contains duplicate networks!");
-        vnm_strdb_destroy(d->strdb);
-        free(d);
-        nlist_destroy(templist);
-        json_decref(toplevel);
-        return NULL;
-    }
+    nlist_finish(templist);
 
     // translate to tree for lookup
     d->tree = nlist_xlate_tree(templist);

-- 
To view, visit https://gerrit.wikimedia.org/r/84013
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib1e6d95ac7ad687933a3e65cdab45ea02ec9e303
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/varnish/libvmod-netmapper
Gerrit-Branch: master
Gerrit-Owner: BBlack <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to