Blame SOURCES/net-snmp-5.7.2-ipCidrRouteTable-duplicates.patch

9a6c41
1172013 - NetworkManager causes snmp OID not increasing
9a6c41
9a6c41
commit 664ed943f63dfe9393e959840ecd23c31c9d8f89
9a6c41
Author: Bill Fenner <fenner@gmail.com>
9a6c41
Date:   Wed Aug 27 16:02:57 2014 -0400
9a6c41
9a6c41
    Handle duplicates in a binary_array container
9a6c41
    
9a6c41
    The CONTAINER_KEY_ALLOW_DUPLICATES setting is fundamentally flawed;
9a6c41
    it really effectively meant "I promise I won't insert duplicates
9a6c41
    so don't check at insert time".  However, the ip-forward-mib
9a6c41
    sets this flag but relies on the duplicate prevention at insert
9a6c41
    time under certain scenarios (e.g., multiple attachments to the
9a6c41
    same subnet on MacOS), resulting in a loop in ip-forward-mib
9a6c41
    in these scenarios.  So, now it means "check for duplicates at
9a6c41
    getnext time" - the binary search will find an arbitrary one
9a6c41
    of the entries with the same key, and when we've incremented
9a6c41
    we have to check whether or not we've actually incremented past
9a6c41
    any duplicates.  This costs an extra key compare per getnext.
9a6c41
    
9a6c41
    If there's a scenario in the future where a MIB implementation
9a6c41
    can really guarantee that it isn't inserting duplicates, we
9a6c41
    might want to add a "CONTAINER_KEY_I_PROMISE_I_WONT_INSERT_DUPLICATES",
9a6c41
    that disables the insertion check but doesn't perform the getnext
9a6c41
    check.
9a6c41
9a6c41
diff --git a/snmplib/container_binary_array.c b/snmplib/container_binary_array.c
9a6c41
index 249a3a9..10ae67f 100644
9a6c41
--- a/snmplib/container_binary_array.c
9a6c41
+++ b/snmplib/container_binary_array.c
9a6c41
@@ -284,6 +284,22 @@ netsnmp_binary_array_get(netsnmp_container *c, const void *key, int exact)
9a6c41
     if (key) {
9a6c41
         if ((index = binary_search(key, c, exact)) == -1)
9a6c41
             return NULL;
9a6c41
+        if (!exact &&
9a6c41
+            c->flags & CONTAINER_KEY_ALLOW_DUPLICATES) {
9a6c41
+            int result;
9a6c41
+
9a6c41
+            /*
9a6c41
+             * If duplicates are allowed, we have to be extra
9a6c41
+             * sure that we didn't just increment to a duplicate,
9a6c41
+             * thus causing a getnext loop.
9a6c41
+             */
9a6c41
+            result = c->compare(t->data[index], key);
9a6c41
+            while (result == 0) {
9a6c41
+                if (++index == t->count)
9a6c41
+                   return NULL;
9a6c41
+                result = c->compare(t->data[index], key);
9a6c41
+            }
9a6c41
+        }
9a6c41
     }
9a6c41
 
9a6c41
     return t->data[index];
9a6c41
diff --git a/testing/fulltests/unit-tests/T021binary_array_oid_duplicates_clib.c b/testing/fulltests/unit-tests/T021binary_array_oid_duplicates_clib.c
9a6c41
new file mode 100644
9a6c41
index 0000000..c027329
9a6c41
--- /dev/null
9a6c41
+++ b/testing/fulltests/unit-tests/T021binary_array_oid_duplicates_clib.c
9a6c41
@@ -0,0 +1,72 @@
9a6c41
+/* HEADER Testing duplicate handling in binary OID array */
9a6c41
+
9a6c41
+/* Much copied from T012 */
9a6c41
+static const char test_name[] = "binary-array-of-OIDs-duplicate-test";
9a6c41
+oid o1 = 1;
9a6c41
+oid o2 = 2;
9a6c41
+oid o3 = 6;
9a6c41
+oid o4 = 8;
9a6c41
+oid o5 = 9;
9a6c41
+oid ox = 7;
9a6c41
+oid oy = 10;
9a6c41
+netsnmp_index i1, i2, i3, i4, i5, ix, iy, *ip;
9a6c41
+netsnmp_index *b[] = { &i4, &i2, &i3, &i1, &i5 };
9a6c41
+netsnmp_container *c;
9a6c41
+int i;
9a6c41
+
9a6c41
+init_snmp(test_name);
9a6c41
+
9a6c41
+c = netsnmp_container_get_binary_array();
9a6c41
+c->compare = netsnmp_compare_netsnmp_index;
9a6c41
+netsnmp_binary_array_options_set(c, 1,
9a6c41
+				 CONTAINER_KEY_ALLOW_DUPLICATES);
9a6c41
+
9a6c41
+i1.oids = &o1;
9a6c41
+i2.oids = &o2;
9a6c41
+i3.oids = &o3;
9a6c41
+i4.oids = &o4;
9a6c41
+i5.oids = &o5;
9a6c41
+ix.oids = &ox;
9a6c41
+iy.oids = &oy;
9a6c41
+i1.len = i2.len = i3.len = i4.len = i5.len = ix.len = iy.len = 1;
9a6c41
+
9a6c41
+for (i = 0; i < sizeof(b)/sizeof(b[0]); ++i)
9a6c41
+    CONTAINER_INSERT(c, b[i]);
9a6c41
+
9a6c41
+#define MAX_ROUNDS 6
9a6c41
+/* Insert some duplicates of i4; also insert a duplicate of
9a6c41
+ * i1 to move the contents of the array around. */
9a6c41
+for (i = 0; i < MAX_ROUNDS; ++i) {
9a6c41
+    switch (i) {
9a6c41
+	case 0:
9a6c41
+	    /* First round: no insert */
9a6c41
+	    break;
9a6c41
+	case 1:
9a6c41
+	case 2:
9a6c41
+	case 4:
9a6c41
+	case 5:
9a6c41
+	    /* Insert another duplicate of our target object */
9a6c41
+	    CONTAINER_INSERT(c, &i4;;
9a6c41
+	    break;
9a6c41
+	case 3:
9a6c41
+	    /* Insert a dulicate of an earlier OID, so that it
9a6c41
+	     * changes the binary search behavior */
9a6c41
+	    CONTAINER_INSERT(c, &i1;;
9a6c41
+	    break;
9a6c41
+    }
9a6c41
+    /* Primary requirement: getnext returns the next value! */
9a6c41
+    ip = CONTAINER_FIND(c, &i4;;
9a6c41
+    OKF(ip, ("FIND returned a value"));
9a6c41
+    OKF(c->compare(&i4, ip) == 0,
9a6c41
+        ("FIND returned oid %" NETSNMP_PRIo "d", ip->oids[0]));
9a6c41
+    ip = CONTAINER_NEXT(c, &i4;;
9a6c41
+    OKF(ip, ("NEXT returned a value"));
9a6c41
+    OKF(c->compare(&i5, ip) == 0,
9a6c41
+        ("NEXT returned index 5 = %" NETSNMP_PRIo "d", i5.oids[0]));
9a6c41
+}
9a6c41
+
9a6c41
+while ((ip = CONTAINER_FIRST(c)))
9a6c41
+  CONTAINER_REMOVE(c, ip);
9a6c41
+CONTAINER_FREE(c);
9a6c41
+
9a6c41
+snmp_shutdown(test_name);