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