Blame SOURCES/net-snmp-5.7.2-ipAddress-faster-load.patch

9a6c41
diff -urNp old/agent/mibgroup/ip-mib/data_access/ipaddress_common.c new/agent/mibgroup/ip-mib/data_access/ipaddress_common.c
9a6c41
--- old/agent/mibgroup/ip-mib/data_access/ipaddress_common.c	2012-10-10 00:28:58.000000000 +0200
9a6c41
+++ new/agent/mibgroup/ip-mib/data_access/ipaddress_common.c	2017-04-04 11:02:42.391951747 +0200
9a6c41
@@ -67,6 +67,7 @@ netsnmp_container *
9a6c41
 netsnmp_access_ipaddress_container_init(u_int flags)
9a6c41
 {
9a6c41
     netsnmp_container *container1;
9a6c41
+    int rc;
9a6c41
 
9a6c41
     DEBUGMSGTL(("access:ipaddress:container", "init\n"));
9a6c41
 
9a6c41
@@ -80,6 +81,7 @@ netsnmp_access_ipaddress_container_init(
9a6c41
         return NULL;
9a6c41
     }
9a6c41
     container1->container_name = strdup("ia_index");
9a6c41
+    CONTAINER_SET_OPTIONS(container1, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
9a6c41
 
9a6c41
     if (flags & NETSNMP_ACCESS_IPADDRESS_INIT_ADDL_IDX_BY_ADDR) {
9a6c41
         netsnmp_container *container2 =
9a6c41
@@ -92,6 +94,13 @@ netsnmp_access_ipaddress_container_init(
9a6c41
         
9a6c41
         container2->compare = _access_ipaddress_entry_compare_addr;
9a6c41
         container2->container_name = strdup("ia_addr");
9a6c41
+
9a6c41
+        /*
9a6c41
+         * With allowed duplicates, CONTAINER_INSERT does not need to sort whole
9a6c41
+         * container and check for duplicates. We remove duplicates manually in
9a6c41
+         * netsnmp_access_ipaddress_container_load.
9a6c41
+         */
9a6c41
+        CONTAINER_SET_OPTIONS(container2, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
9a6c41
         
9a6c41
         netsnmp_container_add_index(container1, container2);
9a6c41
     }
9a6c41
@@ -100,6 +109,53 @@ netsnmp_access_ipaddress_container_init(
9a6c41
 }
9a6c41
 
9a6c41
 /**
9a6c41
+ * Remove duplicate entries from the container.
9a6c41
+ * This function returns new copy of the container and destroys
9a6c41
+ * the original one. Use like this:
9a6c41
+ *   c = _remove_duplicates(c, flags);
9a6c41
+ */
9a6c41
+static netsnmp_container *
9a6c41
+_remove_duplicates(netsnmp_container *container, u_int container_flags)
9a6c41
+{
9a6c41
+       netsnmp_container *c;
9a6c41
+       netsnmp_iterator *it;
9a6c41
+       netsnmp_container *ret;
9a6c41
+       netsnmp_ipaddress_entry *entry, *prev_entry;
9a6c41
+
9a6c41
+       if (! (container_flags & NETSNMP_ACCESS_IPADDRESS_INIT_ADDL_IDX_BY_ADDR)) {
9a6c41
+               /* We don't have address index, we can't detect duplicates */
9a6c41
+               return container;
9a6c41
+       }
9a6c41
+
9a6c41
+       ret = netsnmp_access_ipaddress_container_init(container_flags);
9a6c41
+
9a6c41
+       /* use the IpAddress index */
9a6c41
+       c = container->next;
9a6c41
+       it = CONTAINER_ITERATOR(c);
9a6c41
+       /* Sort the address index */
9a6c41
+       CONTAINER_FIND(c, ITERATOR_FIRST(it));
9a6c41
+
9a6c41
+
9a6c41
+       /*
9a6c41
+        * Sequentially iterate over sorted container and add only unique entries
9a6c41
+        * to 'ret'
9a6c41
+        */
9a6c41
+       prev_entry = NULL;
9a6c41
+       for (entry = ITERATOR_FIRST(it); entry; entry = ITERATOR_NEXT(it)) {
9a6c41
+               if (prev_entry && _access_ipaddress_entry_compare_addr(prev_entry, entry) == 0) {
9a6c41
+                       /* 'entry' is duplicate of the previous one -> delete it */
9a6c41
+                       netsnmp_access_ipaddress_entry_free(entry);
9a6c41
+               } else {
9a6c41
+                       CONTAINER_INSERT(ret, entry);
9a6c41
+                       prev_entry = entry;
9a6c41
+               }
9a6c41
+       }
9a6c41
+       CONTAINER_FREE(container);
9a6c41
+       free(it);
9a6c41
+       return ret;
9a6c41
+}
9a6c41
+
9a6c41
+/**
9a6c41
  * @retval NULL  error
9a6c41
  * @retval !NULL pointer to container
9a6c41
  */
9a6c41
@@ -112,9 +168,10 @@ netsnmp_access_ipaddress_container_load(
9a6c41
 
9a6c41
     DEBUGMSGTL(("access:ipaddress:container", "load\n"));
9a6c41
 
9a6c41
+    if (load_flags & NETSNMP_ACCESS_IPADDRESS_LOAD_ADDL_IDX_BY_ADDR)
9a6c41
+        container_flags |= NETSNMP_ACCESS_IPADDRESS_INIT_ADDL_IDX_BY_ADDR;
9a6c41
+
9a6c41
     if (NULL == container) {
9a6c41
-        if (load_flags & NETSNMP_ACCESS_IPADDRESS_LOAD_ADDL_IDX_BY_ADDR)
9a6c41
-            container_flags |= NETSNMP_ACCESS_IPADDRESS_INIT_ADDL_IDX_BY_ADDR;
9a6c41
         container = netsnmp_access_ipaddress_container_init(container_flags);
9a6c41
     }
9a6c41
     if (NULL == container) {
9a6c41
@@ -129,6 +186,9 @@ netsnmp_access_ipaddress_container_load(
9a6c41
         container = NULL;
9a6c41
     }
9a6c41
 
9a6c41
+    if (container)
9a6c41
+        container = _remove_duplicates(container, container_flags);
9a6c41
+
9a6c41
     return container;
9a6c41
 }
9a6c41
 
9a6c41
diff -urNp old/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable_data_access.c new/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable_data_access.c
9a6c41
--- old/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable_data_access.c	2012-10-10 00:28:58.000000000 +0200
9a6c41
+++ new/agent/mibgroup/ip-mib/ipAddressTable/ipAddressTable_data_access.c	2017-04-04 13:26:34.332529808 +0200
9a6c41
@@ -137,6 +137,13 @@ ipAddressTable_container_init(netsnmp_co
9a6c41
     *container_ptr_ptr =
9a6c41
         netsnmp_container_find("ipAddressTable:table_container");
9a6c41
     if (NULL != *container_ptr_ptr) {
9a6c41
+        /*
9a6c41
+         * The container has ALLOW_DUPLICATES flag to speed up CONTAINER_INSERT
9a6c41
+         * operations (it does not need to check for duplicates), however we
9a6c41
+         * (manually) ensure that we won't insert any duplicates there.
9a6c41
+         */
9a6c41
+        int rc;
9a6c41
+        CONTAINER_SET_OPTIONS(*container_ptr_ptr, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
9a6c41
         (*container_ptr_ptr)->container_name = strdup("ipAddressTable");
9a6c41
         ipAddressTable_container_load(*container_ptr_ptr);
9a6c41
         CONTAINER_FOR_EACH(*container_ptr_ptr,
9a6c41
@@ -205,8 +212,9 @@ static void
9a6c41
 _check_entry_for_updates(ipAddressTable_rowreq_ctx * rowreq_ctx,
9a6c41
                          void **magic)
9a6c41
 {
9a6c41
-    netsnmp_container *ipaddress_container = (netsnmp_container*)magic[0];
9a6c41
+    netsnmp_container *ipaddress_container = magic[0];
9a6c41
     netsnmp_container *to_delete           = (netsnmp_container*)magic[1];
9a6c41
+    netsnmp_container *to_ignore =  (netsnmp_container *) magic[2];
9a6c41
 
9a6c41
     /*
9a6c41
      * check for matching entry using secondary index.
9a6c41
@@ -234,10 +242,21 @@ _check_entry_for_updates(ipAddressTable_
9a6c41
             rowreq_ctx->ipAddressLastChanged = netsnmp_get_agent_uptime();
9a6c41
 
9a6c41
         /*
9a6c41
-         * remove entry from ifcontainer
9a6c41
+         * Remember not to add this entry from 'ipaddress_container' to 'container' later.
9a6c41
+         * Simple CONTAINER_REMOVE(ipaddress_container, ..) would be slow.
9a6c41
          */
9a6c41
-        CONTAINER_REMOVE(ipaddress_container, ipaddress_entry);
9a6c41
-        netsnmp_access_ipaddress_entry_free(ipaddress_entry);
9a6c41
+        if (NULL == to_ignore) {
9a6c41
+            magic[2] = to_ignore = netsnmp_container_find("access_ipaddress:table_container");
9a6c41
+            if (NULL == to_ignore) {
9a6c41
+                snmp_log(LOG_ERR, "couldn't create ignore container\n");
9a6c41
+            } else {
9a6c41
+                /* to speed up insertion */
9a6c41
+                int rc;
9a6c41
+                CONTAINER_SET_OPTIONS(to_ignore, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
9a6c41
+            }
9a6c41
+        }
9a6c41
+        if (NULL != to_ignore)
9a6c41
+            CONTAINER_INSERT(to_ignore, ipaddress_entry);
9a6c41
     }
9a6c41
 }
9a6c41
 
9a6c41
@@ -246,8 +265,11 @@ _check_entry_for_updates(ipAddressTable_
9a6c41
  */
9a6c41
 static void
9a6c41
 _add_new_entry(netsnmp_ipaddress_entry *ipaddress_entry,
9a6c41
-               netsnmp_container *container)
9a6c41
+               void **magic)
9a6c41
 {
9a6c41
+    netsnmp_container *container = magic[0];
9a6c41
+    netsnmp_container *to_ignore = magic[2];
9a6c41
+
9a6c41
     ipAddressTable_rowreq_ctx *rowreq_ctx;
9a6c41
 
9a6c41
     DEBUGMSGTL(("ipAddressTable:access", "creating new entry\n"));
9a6c41
@@ -255,6 +277,11 @@ _add_new_entry(netsnmp_ipaddress_entry *
9a6c41
     netsnmp_assert(NULL != ipaddress_entry);
9a6c41
     netsnmp_assert(NULL != container);
9a6c41
 
9a6c41
+    if (to_ignore && CONTAINER_FIND(to_ignore, ipaddress_entry)) {
9a6c41
+        /* this entry already is in 'container', skip it */
9a6c41
+        return;
9a6c41
+    }
9a6c41
+
9a6c41
     /*
9a6c41
      * allocate an row context and set the index(es)
9a6c41
      */
9a6c41
@@ -329,36 +356,44 @@ int
9a6c41
 ipAddressTable_container_load(netsnmp_container *container)
9a6c41
 {
9a6c41
     netsnmp_container *ipaddress_container;
9a6c41
-    void           *tmp_ptr[2];
9a6c41
+    void           *tmp_ptr[3];
9a6c41
 
9a6c41
     DEBUGMSGTL(("verbose:ipAddressTable:ipAddressTable_cache_load",
9a6c41
                 "called\n"));
9a6c41
 
9a6c41
     /*
9a6c41
-     * TODO:351:M: |-> Load/update data in the ipAddressTable container.
9a6c41
+     * Load/update data in the ipAddressTable container.
9a6c41
      * loop over your ipAddressTable data, allocate a rowreq context,
9a6c41
      * set the index(es) [and data, optionally] and insert into
9a6c41
      * the container.
9a6c41
      */
9a6c41
+    /*
9a6c41
+     * netsnmp_access_ipaddress_container_load makes sure that
9a6c41
+     * ipaddress_container does not contain any duplicate entries,
9a6c41
+     */
9a6c41
+
9a6c41
     ipaddress_container =
9a6c41
         netsnmp_access_ipaddress_container_load(NULL,
9a6c41
                                                 NETSNMP_ACCESS_IPADDRESS_LOAD_ADDL_IDX_BY_ADDR);
9a6c41
     /*
9a6c41
      * we just got a fresh copy of interface data. compare it to
9a6c41
      * what we've already got, and make any adjustments, saving
9a6c41
-     * missing addresses to be deleted.
9a6c41
+     * missing addresses to be deleted. Also, prune interfaces in
9a6c41
+     * ipaddress_container, so only the new interfaces remain.
9a6c41
      */
9a6c41
     tmp_ptr[0] = ipaddress_container->next;
9a6c41
-    tmp_ptr[1] = NULL;
9a6c41
+    tmp_ptr[1] = NULL; /* list of interfaces to be removed from 'container' */
9a6c41
+    tmp_ptr[2] = NULL; /* list of interfaces to be ignored in ipaddress_container */
9a6c41
     CONTAINER_FOR_EACH(container, (netsnmp_container_obj_func *)
9a6c41
                        _check_entry_for_updates, tmp_ptr);
9a6c41
 
9a6c41
     /*
9a6c41
      * now add any new interfaces
9a6c41
      */
9a6c41
+    tmp_ptr[0] = container;
9a6c41
     CONTAINER_FOR_EACH(ipaddress_container,
9a6c41
                        (netsnmp_container_obj_func *) _add_new_entry,
9a6c41
-                       container);
9a6c41
+                       tmp_ptr);
9a6c41
 
9a6c41
     /*
9a6c41
      * free the container. we've either claimed each entry, or released it,
9a6c41
@@ -396,6 +431,19 @@ ipAddressTable_container_load(netsnmp_co
9a6c41
              */
9a6c41
             CONTAINER_REMOVE(tmp_container, NULL);
9a6c41
         }
9a6c41
+        CONTAINER_FREE(tmp_container);
9a6c41
+    }
9a6c41
+
9a6c41
+    if (NULL != tmp_ptr[2]) {
9a6c41
+        /* list of interfaces to be ignored in ipaddress_container - free it */
9a6c41
+        netsnmp_container *to_ignore = (netsnmp_container *) tmp_ptr[2];
9a6c41
+        netsnmp_ipaddress_entry *ipaddress_entry;
9a6c41
+        while (CONTAINER_SIZE(to_ignore)) {
9a6c41
+            ipaddress_entry = (netsnmp_ipaddress_entry*)CONTAINER_FIRST(to_ignore);
9a6c41
+            CONTAINER_REMOVE(to_ignore, ipaddress_entry);
9a6c41
+            netsnmp_access_ipaddress_entry_free(ipaddress_entry);
9a6c41
+        }
9a6c41
+        CONTAINER_FREE(to_ignore);
9a6c41
     }
9a6c41
 
9a6c41
     DEBUGMSGT(("verbose:ipAddressTable:ipAddressTable_cache_load",
9a6c41
diff -urNp old/agent/mibgroup/mibII/ipAddr.c new/agent/mibgroup/mibII/ipAddr.c
9a6c41
--- old/agent/mibgroup/mibII/ipAddr.c	2012-10-10 00:28:58.000000000 +0200
9a6c41
+++ new/agent/mibgroup/mibII/ipAddr.c	2017-04-04 13:28:56.547268946 +0200
9a6c41
@@ -493,14 +493,16 @@ Address_Scan_Next(Index, Retin_ifaddr)
9a6c41
 }
9a6c41
 
9a6c41
 #elif defined(linux)
9a6c41
+#include <errno.h>
9a6c41
 static struct ifreq *ifr;
9a6c41
 static int ifr_counter;
9a6c41
 
9a6c41
 static void
9a6c41
 Address_Scan_Init(void)
9a6c41
 {
9a6c41
-    int num_interfaces = 0;
9a6c41
+    int i;
9a6c41
     int fd;
9a6c41
+    int lastlen = 0;
9a6c41
 
9a6c41
     /* get info about all interfaces */
9a6c41
 
9a6c41
@@ -508,30 +510,45 @@ Address_Scan_Init(void)
9a6c41
     SNMP_FREE(ifc.ifc_buf);
9a6c41
     ifr_counter = 0;
9a6c41
 
9a6c41
-    do
9a6c41
+    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
9a6c41
     {
9a6c41
-	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
9a6c41
-	{
9a6c41
-	    DEBUGMSGTL(("snmpd", "socket open failure in Address_Scan_Init\n"));
9a6c41
-	    return;
9a6c41
-	}
9a6c41
-	num_interfaces += 16;
9a6c41
-
9a6c41
-	ifc.ifc_len = sizeof(struct ifreq) * num_interfaces;
9a6c41
-	ifc.ifc_buf = (char*) realloc(ifc.ifc_buf, ifc.ifc_len);
9a6c41
-	
9a6c41
-	    if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
9a6c41
-	    {
9a6c41
-		ifr=NULL;
9a6c41
-		close(fd);
9a6c41
-	   	return;
9a6c41
-	    }
9a6c41
-	    close(fd);
9a6c41
+        DEBUGMSGTL(("snmpd", "socket open failure in Address_Scan_Init\n"));
9a6c41
+        return;	   
9a6c41
+    }
9a6c41
+
9a6c41
+    /*
9a6c41
+     * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF
9a6c41
+     * on some platforms; see W. R. Stevens, ``Unix Network Programming
9a6c41
+     * Volume I'', p.435...
9a6c41
+     */
9a6c41
+
9a6c41
+    for (i = 8;; i *= 2) {
9a6c41
+        ifc.ifc_len = sizeof(struct ifreq) * i;
9a6c41
+        ifc.ifc_req = calloc(i, sizeof(struct ifreq));
9a6c41
+
9a6c41
+        if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
9a6c41
+            if (errno != EINVAL || lastlen != 0) {
9a6c41
+                /*
9a6c41
+                 * Something has gone genuinely wrong...
9a6c41
+                 */
9a6c41
+                snmp_log(LOG_ERR, "bad rc from ioctl, errno %d", errno);
9a6c41
+                SNMP_FREE(ifc.ifc_buf);
9a6c41
+                close(fd);
9a6c41
+                return;
9a6c41
+            }
9a6c41
+        } else {
9a6c41
+            if (ifc.ifc_len == lastlen) {
9a6c41
+                /*
9a6c41
+                 * The length is the same as the last time; we're done...
9a6c41
+                 */
9a6c41
+                break;
9a6c41
+            }
9a6c41
+            lastlen = ifc.ifc_len;
9a6c41
+        }
9a6c41
+        free(ifc.ifc_buf); /* no SNMP_FREE, getting ready to reassign */
9a6c41
     }
9a6c41
-    while (ifc.ifc_len >= (sizeof(struct ifreq) * num_interfaces));
9a6c41
-    
9a6c41
-    ifr = ifc.ifc_req;
9a6c41
     close(fd);
9a6c41
+    ifr = ifc.ifc_req;
9a6c41
 }
9a6c41
 
9a6c41
 /*