Author: eugen
Date: Sat Aug 18 10:58:44 2018
New Revision: 338013
URL: https://svnweb.freebsd.org/changeset/base/338013

Log:
  bsnmpd(8): fix and optimize interface description processing
  
  * correctly prepare a buffer to obtain interface description from a kernel and
    truncate long description instead of dropping it altogether and
    spamming logs;
  * skip calling strlen() for each description and each SNMP request
    for MIB-II/ifXTable's ifAlias.
  * teach bsnmpd to allocate memory dynamically for interface descriptions
    to decrease memory usage for common case and not to break
    if long description occurs;
  
  PR:                   217763
  Reviewed by:          harti and others
  MFC after:            1 week
  Differential Revision:        https://reviews.freebsd.org/D16459

Modified:
  head/contrib/bsnmp/snmp_mibII/mibII.c
  head/contrib/bsnmp/snmp_mibII/mibII.h
  head/contrib/bsnmp/snmp_mibII/mibII_interfaces.c
  head/contrib/bsnmp/snmp_mibII/snmp_mibII.h

Modified: head/contrib/bsnmp/snmp_mibII/mibII.c
==============================================================================
--- head/contrib/bsnmp/snmp_mibII/mibII.c       Sat Aug 18 10:14:02 2018        
(r338012)
+++ head/contrib/bsnmp/snmp_mibII/mibII.c       Sat Aug 18 10:58:44 2018        
(r338013)
@@ -439,11 +439,15 @@ mibif_restart_mibII_poll_timer(void)
 int
 mib_fetch_ifmib(struct mibif *ifp)
 {
+       static int kmib[2] = { -1, 0 }; /* for sysctl net.ifdescr_maxlen */
+
        int name[6];
+       size_t kmiblen = nitems(kmib);
        size_t len;
        void *newmib;
        struct ifmibdata oldmib = ifp->mib;
        struct ifreq irr;
+       unsigned int alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
 
        if (fetch_generic_mib(ifp, &oldmib) == -1)
                return (-1);
@@ -515,18 +519,69 @@ mib_fetch_ifmib(struct mibif *ifp)
        }
 
   out:
+
+       /*
+        * Find sysctl mib for net.ifdescr_maxlen (one time).
+        * kmib[0] == -1 at first call to mib_fetch_ifmib().
+        * Then kmib[0] > 0 if we found sysctl mib for net.ifdescr_maxlen.
+        * Else, kmib[0] == 0 (unexpected error from a kernel).
+        */
+       if (kmib[0] < 0 &&
+           sysctlnametomib("net.ifdescr_maxlen", kmib, &kmiblen) < 0) {
+               kmib[0] = 0;
+               syslog(LOG_WARNING, "sysctlnametomib net.ifdescr_maxlen: %m");
+       }
+
+       /*
+        * Fetch net.ifdescr_maxlen value every time to catch up with changes.
+        */
+       len = sizeof(alias_maxlen);
+       if (kmib[0] > 0 && sysctl(kmib, 2, &alias_maxlen, &len, NULL, 0) < 0) {
+               /* unexpected error from the kernel, use default value */
+               alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
+               syslog(LOG_WARNING, "sysctl net.ifdescr_maxlen: %m");
+       }
+
+       /*
+        * Kernel limit might be decreased after interfaces got
+        * their descriptions assigned. Try to obtain them anyway.
+        */
+       if (alias_maxlen == 0)
+               alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
+
+       /*
+        * Allocate maximum memory for a buffer and later reallocate
+        * to free extra memory.
+        */
+       if ((ifp->alias = malloc(alias_maxlen)) == NULL) {
+               syslog(LOG_WARNING, "malloc(%d) failed: %m", (int)alias_maxlen);
+               goto fin;
+       }
+
        strlcpy(irr.ifr_name, ifp->name, sizeof(irr.ifr_name));
-       irr.ifr_buffer.buffer = MIBIF_PRIV(ifp)->alias;
-       irr.ifr_buffer.length = sizeof(MIBIF_PRIV(ifp)->alias);
+       irr.ifr_buffer.buffer = ifp->alias;
+       irr.ifr_buffer.length = alias_maxlen;
        if (ioctl(mib_netsock, SIOCGIFDESCR, &irr) == -1) {
-               MIBIF_PRIV(ifp)->alias[0] = 0;
+               free(ifp->alias);
+               ifp->alias = NULL;
                if (errno != ENOMSG)
                        syslog(LOG_WARNING, "SIOCGIFDESCR (%s): %m", ifp->name);
        } else if (irr.ifr_buffer.buffer == NULL) {
-               MIBIF_PRIV(ifp)->alias[0] = 0;
+               free(ifp->alias);
+               ifp->alias = NULL;
                syslog(LOG_WARNING, "SIOCGIFDESCR (%s): too long (%zu)",
                    ifp->name, irr.ifr_buffer.length);
+       } else {
+               ifp->alias_size = strnlen(ifp->alias, alias_maxlen) + 1;
+
+               if (ifp->alias_size > MIBIF_ALIAS_SIZE)
+                   ifp->alias_size = MIBIF_ALIAS_SIZE; 
+
+               if (ifp->alias_size < alias_maxlen)
+                       ifp->alias = realloc(ifp->alias, ifp->alias_size);
        }
+
+fin:
        ifp->mibtick = get_ticks();
        return (0);
 }
@@ -706,6 +761,10 @@ mibif_free(struct mibif *ifp)
                mibif_reset_hc_timer();
        }
 
+       if (ifp->alias != NULL) {
+               free(ifp->alias);
+               ifp->alias = NULL;
+       }
        free(ifp->private);
        ifp->private = NULL;
        free(ifp->physaddr);

Modified: head/contrib/bsnmp/snmp_mibII/mibII.h
==============================================================================
--- head/contrib/bsnmp/snmp_mibII/mibII.h       Sat Aug 18 10:14:02 2018        
(r338012)
+++ head/contrib/bsnmp/snmp_mibII/mibII.h       Sat Aug 18 10:58:44 2018        
(r338013)
@@ -57,8 +57,9 @@
 #include "snmp_mibII.h"
 #include "mibII_tree.h"
 
-/* maximum size of the interface alias */
+/* maximum size of the interface alias unless overridden with 
net.ifdescr_maxlen */
 #define        MIBIF_ALIAS_SIZE        (64 + 1)
+#define        MIBIF_ALIAS_SIZE_MAX    1024
 
 /*
  * Interface list and flags.
@@ -81,8 +82,6 @@ struct mibif_private {
        uint64_t        hc_imcasts;
        uint64_t        hc_ipackets;
 
-       /* this should be made public */
-       char            alias[MIBIF_ALIAS_SIZE];
 };
 #define        MIBIF_PRIV(IFP) ((struct mibif_private *)((IFP)->private))
 

Modified: head/contrib/bsnmp/snmp_mibII/mibII_interfaces.c
==============================================================================
--- head/contrib/bsnmp/snmp_mibII/mibII_interfaces.c    Sat Aug 18 10:14:02 
2018        (r338012)
+++ head/contrib/bsnmp/snmp_mibII/mibII_interfaces.c    Sat Aug 18 10:58:44 
2018        (r338013)
@@ -528,7 +528,7 @@ op_ifxtable(struct snmp_context *ctx, struct snmp_valu
                break;
 
          case LEAF_ifAlias:
-               ret = string_get(value, MIBIF_PRIV(ifp)->alias, -1);
+               ret = string_get(value, ifp->alias, ifp->alias_size - 1);
                break;
 
          case LEAF_ifCounterDiscontinuityTime:

Modified: head/contrib/bsnmp/snmp_mibII/snmp_mibII.h
==============================================================================
--- head/contrib/bsnmp/snmp_mibII/snmp_mibII.h  Sat Aug 18 10:14:02 2018        
(r338012)
+++ head/contrib/bsnmp/snmp_mibII/snmp_mibII.h  Sat Aug 18 10:58:44 2018        
(r338013)
@@ -80,6 +80,9 @@ struct mibif {
        /* to be set by ifType specific modules. This is ifSpecific. */
        struct asn_oid  spec_oid;
 
+       char            *alias;
+       size_t          alias_size;
+
        /* private data - don't touch */
        void            *private;
 };
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to