]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Add two switches for max IPv4/6 routes to gather
authorOliver Kurth <okurth@vmware.com>
Tue, 19 Jun 2018 18:07:44 +0000 (11:07 -0700)
committerOliver Kurth <okurth@vmware.com>
Tue, 19 Jun 2018 18:07:44 +0000 (11:07 -0700)
Gathering nic info in a Linux guest OS which is configured with large
number(60000+) of ipv6 routes could result in vmtoolsd process taking a
long time and rock solid 100% CPU of a core.  Though tools only exports
at most NICINFO_MAX_ROUTES(100) routes, it tries to read all the contents
of /proc/net/ipv6_route which costs too much time because:
1. IPv6 route table is not efficient natively compared to ipv4 due to
   its implementation.
2. The g_io library can aggravate the performance.

On the other hand, when gathering routes, IPv4 comes first, and IPv6 second.
And the routes reported to VMX has an overall limitation of serializing
(NICINFO_MAX_ROUTES).  If there's more than NICINFO_MAX_ROUTES IPv4 routes
in system, no IPv6 will get reported.

Added two switches "max-ipv4-routes" and "max-ipv6-routes"
(NICINFO_MAX_ROUTES by default) in tools.conf and let SlashProcNet_GetRoute*()
only read the first max ipv4/6 routes lines of /proc/net/[ipv6_]route to avoid
performance problem.  Users can disable ipv4/ipv6 routes gathering
separately if they want ipv6 or ipv4 only.

open-vm-tools/lib/include/conf.h
open-vm-tools/lib/include/nicInfo.h
open-vm-tools/lib/include/slashProc.h
open-vm-tools/lib/nicInfo/nicInfo.c
open-vm-tools/lib/nicInfo/nicInfoInt.h
open-vm-tools/lib/nicInfo/nicInfoPosix.c
open-vm-tools/lib/slashProc/net.c
open-vm-tools/services/plugins/guestInfo/guestInfoServer.c
open-vm-tools/toolbox/toolboxcmd-info.c

index 185e89bcfd42e2c1ded63a5b414fb85008763d63..af685348750d58a15709424dfabfaaf92933c1ad 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2002-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2002-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
 
 #define CONFNAME_GUESTINFO_EXCLUDENICS "exclude-nics"
 
+/**
+ * Define a custom max IPv4 routes to gather.
+ *
+ * @note Illegal values result in a @c g_warning and fallback to the default
+ * NICINFO_MAX_ROUTES.
+ *
+ * @param int   User-defined max routes with range [0, NICINFO_MAX_ROUTES].
+ *              Set to 0 to disable gathering.
+ */
+#define CONFNAME_GUESTINFO_MAXIPV4ROUTES "max-ipv4-routes"
+
+/**
+ * Define a custom max IPv6 routes to gather.
+ *
+ * @note Illegal values result in a @c g_warning and fallback to the default
+ * NICINFO_MAX_ROUTES.
+ *
+ * @param int   User-defined max routes with range [0, NICINFO_MAX_ROUTES].
+ *              Set to 0 to disable gathering.
+ */
+#define CONFNAME_GUESTINFO_MAXIPV6ROUTES "max-ipv6-routes"
+
 /**
  * Lets user include reserved space in diskInfo space metrics on Linux.
  *
index 5f26ddec0d4a08fa053ec1806254359930f40dfa..59b28b85156e4c4d58ff3e5f691b7a7301cd448b 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2014-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2014-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -39,7 +39,9 @@ typedef enum {
 } NicInfoPriority;
 
 Bool GuestInfo_GetFqdn(int outBufLen, char fqdn[]);
-Bool GuestInfo_GetNicInfo(NicInfoV3 **nicInfo);
+Bool GuestInfo_GetNicInfo(unsigned int maxIPv4Routes,
+                          unsigned int maxIPv6Routes,
+                          NicInfoV3 **nicInfo);
 void GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo);
 char *GuestInfo_GetPrimaryIP(void);
 
index e6c8dcdb584fd434358bbe11949242d9ed9c3b79..c5d9b40e06349ad558828f86a45602f1a82ed61f 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2009-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
 EXTERN GHashTable *SlashProcNet_GetSnmp(void);
 EXTERN GHashTable *SlashProcNet_GetSnmp6(void);
 
-EXTERN GPtrArray  *SlashProcNet_GetRoute(void);
+EXTERN GPtrArray  *SlashProcNet_GetRoute(unsigned int, unsigned short);
 EXTERN void        SlashProcNet_FreeRoute(GPtrArray *);
 
-EXTERN GPtrArray  *SlashProcNet_GetRoute6(void);
+EXTERN GPtrArray  *SlashProcNet_GetRoute6(unsigned int, unsigned int);
 EXTERN void        SlashProcNet_FreeRoute6(GPtrArray *);
 
 #endif // ifndef _SLASHPROC_H_
index 7ec8320fe7e6e9ce968096f96100f37526ab963c..ce9ebae38e8ac2fd14e26141eda64f6809cf842e 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2014-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2014-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -281,7 +281,9 @@ GuestInfo_GetFqdn(int outBufLen,
  *
  * @brief Returns guest networking configuration (and some runtime state).
  *
- * @param[out] nicInfo  Will point to a newly allocated NicInfo.
+ * @param[in]  maxIPv4Routes  Max IPv4 routes to gather.
+ * @param[in]  maxIPv6Routes  Max IPv6 routes to gather.
+ * @param[out] nicInfo        Will point to a newly allocated NicInfo.
  *
  * @note
  * Caller is responsible for freeing @a nicInfo with GuestInfo_FreeNicInfo.
@@ -293,13 +295,15 @@ GuestInfo_GetFqdn(int outBufLen,
  */
 
 Bool
-GuestInfo_GetNicInfo(NicInfoV3 **nicInfo)
+GuestInfo_GetNicInfo(unsigned int maxIPv4Routes,
+                     unsigned int maxIPv6Routes,
+                     NicInfoV3 **nicInfo)
 {
    Bool retval = FALSE;
 
    *nicInfo = Util_SafeCalloc(1, sizeof (struct NicInfoV3));
 
-   retval = GuestInfoGetNicInfo(*nicInfo);
+   retval = GuestInfoGetNicInfo(maxIPv4Routes, maxIPv6Routes, *nicInfo);
    if (!retval) {
       GuestInfo_FreeNicInfo(*nicInfo);
       *nicInfo = NULL;
index 4afe58166a2d12c087bb89766b93ff8b7268b1ee..1fac8024c2d70fecd4142780ebecbf59ca9f08b0 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2014-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2014-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -34,7 +34,9 @@
 #endif
 
 Bool GuestInfoGetFqdn(int outBufLen, char fqdn[]);
-Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo);
+Bool GuestInfoGetNicInfo(unsigned int maxIPv4Routes,   // IN
+                         unsigned int maxIPv6Routes,   // IN
+                         NicInfoV3 *nicInfo);          // OUT
 
 GuestNicV3 *GuestInfoAddNicEntry(NicInfoV3 *nicInfo,                    // IN/OUT
                                  const char macAddress[NICINFO_MAC_LEN], // IN
index 818e61e723c03e37a6bf1ce237de2e23efc4948e..8a063a0801f4194d19ebe28019264f95f0e47742 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2014-2017 VMware, Inc. All rights reserved.
+ * Copyright (C) 2014-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -139,7 +139,9 @@ static int ReadInterfaceDetailsNormal(const struct intf_entry *entry,
                                       void *arg);
 static int ReadInterfaceDetailsLowPriority(const struct intf_entry *entry,
                                            void *arg);
-static Bool RecordRoutingInfo(NicInfoV3 *nicInfo);
+static Bool RecordRoutingInfo(unsigned int maxIPv4Routes,
+                              unsigned int maxIPv6Routes,
+                              NicInfoV3 *nicInfo);
 
 #if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(USERWORLD)
 typedef struct GuestInfoIpPriority {
@@ -152,7 +154,9 @@ static int GuestInfoGetIntf(const struct intf_entry *entry, void *arg);
 
 #endif
 
-static Bool RecordRoutingInfo(NicInfoV3 *nicInfo);
+static Bool RecordRoutingInfo(unsigned int maxIPv4Routes,
+                              unsigned int maxIPv6Routes,
+                              NicInfoV3 *nicInfo);
 
 static char *ValidateConvertAddress(const struct sockaddr *addr);
 
@@ -336,12 +340,19 @@ GuestInfoGetInterface(struct ifaddrs *ifaddrs,
  ******************************************************************************
  * GuestInfoGetNicInfo --                                                */ /**
  *
+ * @param[in]  maxIPv4Routes  Max IPv4 routes to gather.
+ * @param[in]  maxIPv6Routes  Max IPv6 routes to gather.
+ * @param[out] nicInfo        NicInfoV3 container.
+ *
  * @copydoc GuestInfo_GetNicInfo
  *
  ******************************************************************************
  */
 
-Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
+Bool
+GuestInfoGetNicInfo(unsigned int maxIPv4Routes,
+                    unsigned int maxIPv6Routes,
+                    NicInfoV3 *nicInfo)
 {
 #ifndef NO_DNET
    intf_t *intf;
@@ -374,7 +385,8 @@ Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
    }
 #endif
 
-   if (!RecordRoutingInfo(nicInfo)) {
+   if ((maxIPv4Routes > 0 || maxIPv6Routes > 0) &&
+       !RecordRoutingInfo(maxIPv4Routes, maxIPv6Routes, nicInfo)) {
       return FALSE;
    }
 
@@ -402,13 +414,16 @@ Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
    }
 #endif
 
-   if (!RecordRoutingInfo(nicInfo)) {
+   if ((maxIPv4Routes > 0 || maxIPv6Routes > 0) &&
+       !RecordRoutingInfo(maxIPv4Routes, maxIPv6Routes, nicInfo)) {
       return FALSE;
    }
 
    return TRUE;
 #else
-   RecordRoutingInfo(nicInfo);
+   (void)maxIPv4Routes;
+   (void)maxIPv6Routes;
+   (void)nicInfo;
 
    return FALSE;
 #endif
@@ -913,7 +928,8 @@ RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
  * @brief Query the IPv4 routing subsystem and pack up contents
  * (struct rtentry) into InetCidrRouteEntries.
  *
- * @param[out] nicInfo  NicInfoV3 container.
+ * @param[in]  maxRoutes   Max routes to gather.
+ * @param[out] nicInfo     NicInfoV3 container.
  *
  * @note Do not call this routine without first populating @a nicInfo 's NIC
  * list.
@@ -925,13 +941,16 @@ RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
  */
 
 static Bool
-RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
+RecordRoutingInfoIPv4(unsigned int maxRoutes,
+                      NicInfoV3 *nicInfo)
 {
    GPtrArray *routes = NULL;
    guint i;
    Bool ret = FALSE;
 
-   if ((routes = SlashProcNet_GetRoute()) == NULL) {
+   ASSERT(maxRoutes > 0);
+
+   if ((routes = SlashProcNet_GetRoute(maxRoutes, RTF_UP)) == NULL) {
       return FALSE;
    }
 
@@ -952,8 +971,7 @@ RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
 
       rtentry = g_ptr_array_index(routes, i);
 
-      if ((rtentry->rt_flags & RTF_UP) == 0 ||
-          !GuestInfoGetNicInfoIfIndex(nicInfo,
+      if (!GuestInfoGetNicInfoIfIndex(nicInfo,
                                       if_nametoindex(rtentry->rt_dev),
                                       &ifIndex)) {
          continue;
@@ -1002,7 +1020,8 @@ RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
  * @brief Query the IPv6 routing subsystem and pack up contents
  * (struct in6_rtmsg) into InetCidrRouteEntries.
  *
- * @param[out] nicInfo  NicInfoV3 container.
+ * @param[in]  maxRoutes   Max routes to gather.
+ * @param[out] nicInfo     NicInfoV3 container.
  *
  * @note Do not call this routine without first populating @a nicInfo 's NIC
  * list.
@@ -1014,13 +1033,25 @@ RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
  */
 
 static Bool
-RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
+RecordRoutingInfoIPv6(unsigned int maxRoutes,
+                      NicInfoV3 *nicInfo)
 {
    GPtrArray *routes = NULL;
    guint i;
    Bool ret = FALSE;
 
-   if ((routes = SlashProcNet_GetRoute6()) == NULL) {
+   ASSERT(maxRoutes > 0);
+
+   /*
+    * Reading large number of ipv6 routes in pathToNetRoute6 could
+    * result in performance issue because:
+    *  1. IPv6 route table is not efficient natively compared to ipv4
+    *     because of its implementation.
+    *  2. The glib I/O channel can aggravate the performace.
+    * Considering bug 605821/2064541, we try to read the first maxRoutes
+    * lines of pathToNetRoute6 with route flag RTF_UP set.
+    */
+   if ((routes = SlashProcNet_GetRoute6(maxRoutes, RTF_UP)) == NULL) {
       return FALSE;
    }
 
@@ -1040,8 +1071,7 @@ RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
 
       in6_rtmsg = g_ptr_array_index(routes, i);
 
-      if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 ||
-          !GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
+      if (!GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
                                       &ifIndex)) {
          continue;
       }
@@ -1090,7 +1120,11 @@ RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
  * @brief Query the routing subsystem and pack up contents into
  * InetCidrRouteEntries when either of IPv4 or IPV6 is configured.
  *
- * @param[out] nicInfo  NicInfoV3 container.
+ * @param[in]  maxIPv4Routes  Max IPv4 routes to gather.
+                              Set 0 to disable gathering.
+ * @param[in]  maxIPv6Routes  Max IPv6 routes to gather.
+                              Set 0 to disable gathering.
+ * @param[out] nicInfo        NicInfoV3 container.
  *
  * @note Do not call this routine without first populating @a nicInfo 's NIC
  * list.
@@ -1103,19 +1137,36 @@ RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
  */
 
 static Bool
-RecordRoutingInfo(NicInfoV3 *nicInfo)
+RecordRoutingInfo(unsigned int maxIPv4Routes,
+                  unsigned int maxIPv6Routes,
+                  NicInfoV3 *nicInfo)
 {
-   Bool retIPv4 = TRUE;
-   Bool retIPv6 = TRUE;
+   Bool retIPv4 = FALSE;
+   Bool retIPv6 = FALSE;
+
+   ASSERT(maxIPv4Routes > 0 || maxIPv6Routes > 0);
 
-   if (File_Exists("/proc/net/route") && !RecordRoutingInfoIPv4(nicInfo)) {
-      g_warning("%s: Unable to collect IPv4 routing table.\n", __func__);
-      retIPv4 = FALSE;
+   /*
+    * We gather IPv4 routes first, then IPv6. This means IPv4 routes are more
+    * prioritized than IPv6. When there's more than NICINFO_MAX_ROUTES IPv4
+    * routes in system, the IPv6 routes will be ignored. A more equitable
+    * design might be getting max IPv4 and IPv6 routes first, and then pick
+    * out the head NICINFO_MAX_ROUTES/2 of each route list.
+    */
+   if (maxIPv4Routes > 0) {
+      if (RecordRoutingInfoIPv4(maxIPv4Routes, nicInfo)) {
+         retIPv4 = TRUE;
+      } else {
+         g_warning("%s: Unable to collect IPv4 routing table.\n", __func__);
+      }
    }
 
-   if (File_Exists("/proc/net/ipv6_route") && !RecordRoutingInfoIPv6(nicInfo)) {
-      g_warning("%s: Unable to collect IPv6 routing table.\n", __func__);
-      retIPv6 = FALSE;
+   if (maxIPv6Routes > 0 && nicInfo->routes.routes_len < NICINFO_MAX_ROUTES) {
+      if (RecordRoutingInfoIPv6(maxIPv6Routes, nicInfo)) {
+         retIPv6 = TRUE;
+      } else {
+         g_warning("%s: Unable to collect IPv6 routing table.\n", __func__);
+      }
    }
 
    return (retIPv4 || retIPv6);
@@ -1123,7 +1174,9 @@ RecordRoutingInfo(NicInfoV3 *nicInfo)
 
 #else                                           // ifdef USE_SLASH_PROC
 static Bool
-RecordRoutingInfo(NicInfoV3 *nicInfo)
+RecordRoutingInfo(unsigned int maxIPv4Routes,
+                  unsigned int maxIPv6Routes,
+                  NicInfoV3 *nicInfo)
 {
    return TRUE;
 }
index 1d2a888004eb5393c27216394cd6398e20c870b5..82b69638fbcb6a80fa0481549ba78f27927bfe17 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2009-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -495,14 +495,14 @@ SlashProcNet_GetSnmp6(void)
  ******************************************************************************
  * SlashProcNet_GetRoute --                                             */ /**
  *
- * @brief Reads @ref pathToNetRoute and returns a @c GPtrArray of
- *        <tt>struct rtentry</tt>s.
+ * @brief Reads the first @c maxRoutes lines of @ref pathToNetRoute and
+ *        returns a @c GPtrArray of <tt>struct rtentry</tt>s.
  *
  * Example usage:
  * @code
  * GPtrArray *rtArray;
  * guint i;
- * rtArray = SlashProcNet_GetRoute();
+ * rtArray = SlashProcNet_GetRoute(NICINFO_MAX_ROUTES, RTF_UP);
  * for (i = 0; i < rtArray->len; i++) {
  *    struct rtentry *myRoute = g_ptr_array_index(rtArray, i);
  *    // Do something with myRoute->rt_dst.
@@ -514,6 +514,10 @@ SlashProcNet_GetSnmp6(void)
  *              SlashProcNet_FreeRoute.
  * @note        This routine creates persistent GLib GRegexs.
  *
+ * @param[in]   maxRoutes       Max routes to gather.
+ * @param[in]   rtFilterFlags   Route flags used to filter out what we want.
+ *                              Set ~0 if want everything.
+ *
  * @return      On failure, NULL.  On success, a valid @c GPtrArray.
  * @todo        Consider init/cleanup routines to not "leak" GRegexs.
  * @todo        Consider rewriting, integrating with libdnet.
@@ -522,17 +526,21 @@ SlashProcNet_GetSnmp6(void)
  */
 
 GPtrArray *
-SlashProcNet_GetRoute(void)
+SlashProcNet_GetRoute(unsigned int maxRoutes,
+                      unsigned short rtFilterFlags)
 {
    GIOChannel *myChannel = NULL;
    GIOStatus myIoStatus;
    GPtrArray *myArray = NULL;
    gchar *myLine = NULL;
    int fd = -1;
+   unsigned int lineCount = 0;
 
    static GRegex *myFieldsRE = NULL;
    static GRegex *myValuesRE = NULL;
 
+   ASSERT(maxRoutes > 0);
+
    if (myFieldsRE == NULL) {
       myFieldsRE = g_regex_new("^Iface\\s+Destination\\s+Gateway\\s+Flags\\s+"
                                "RefCnt\\s+Use\\s+Metric\\s+Mask\\s+MTU\\s+"
@@ -579,8 +587,9 @@ SlashProcNet_GetRoute(void)
     * 3.  For each line...
     */
 
-   while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL,
-                                               NULL)) == G_IO_STATUS_NORMAL) {
+   while (lineCount < maxRoutes &&
+             (myIoStatus = g_io_channel_read_line(myChannel,
+                  &myLine, NULL, NULL, NULL)) == G_IO_STATUS_NORMAL) {
       GMatchInfo *myMatchInfo = NULL;
       struct rtentry *myEntry = NULL;
       struct sockaddr_in *sin = NULL;
@@ -591,7 +600,7 @@ SlashProcNet_GetRoute(void)
        */
       if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) {
          parseError = TRUE;
-         goto badIteration;
+         goto iterationCleanup;
       }
 
       /*
@@ -599,7 +608,6 @@ SlashProcNet_GetRoute(void)
        *     code path.
        */
       myEntry = g_new0(struct rtentry, 1);
-      g_ptr_array_add(myArray, myEntry);
 
       /*
        * 3c. Copy contents to new struct rtentry.
@@ -623,7 +631,16 @@ SlashProcNet_GetRoute(void)
       myEntry->rt_mtu = MatchToGuint64(myMatchInfo, 7, 10);
       myEntry->rt_irtt = MatchToGuint64(myMatchInfo, 8, 10);
 
-badIteration:
+      if (rtFilterFlags == (unsigned short)~0 ||
+          (myEntry->rt_flags & rtFilterFlags) != 0) {
+         g_ptr_array_add(myArray, myEntry);
+         lineCount++;
+      } else {
+         g_free(myEntry->rt_dev);
+         g_free(myEntry);
+      }
+
+iterationCleanup:
       g_free(myLine);
       myLine = NULL;
 
@@ -631,15 +648,15 @@ badIteration:
       myMatchInfo = NULL;
 
       if (parseError) {
+         /* Return NULL to signal parsing error */
+         if (myArray) {
+            SlashProcNet_FreeRoute(myArray);
+            myArray = NULL;
+         }
          break;
       }
    }
 
-   if (myArray && myIoStatus != G_IO_STATUS_EOF) {
-      SlashProcNet_FreeRoute(myArray);
-      myArray = NULL;
-   }
-
 out:
    g_free(myLine);
    close(fd);
@@ -685,25 +702,29 @@ SlashProcNet_FreeRoute(GPtrArray *routeArray)
  ******************************************************************************
  * SlashProcNet_GetRoute6 --                                            */ /**
  *
- * @brief Reads @ref pathToNetRoute6 and returns a @c GPtrArray of
- *        <tt>struct in6_rtmsg</tt>s.
+ * @brief Reads the first @c maxRoutes lines of @ref pathToNetRoute6 and
+ *        returns a @c GPtrArray of <tt>struct in6_rtmsg</tt>s.
  *
  * Example usage:
  * @code
  * GPtrArray *rtArray;
  * guint i;
- * rtArray = SlashProcNet_GetRoute6();
+ * rtArray = SlashProcNet_GetRoute6(NICINFO_MAX_ROUTES, RTF_UP);
  * for (i = 0; i < rtArray->len; i++) {
  *    struct in6_rtmsg *myRoute = g_ptr_array_index(rtArray, i);
  *    // Do something with myRoute->rtmsg_dst.
  * }
- * SlashProcNet_FreeRoute6(rtArray, TRUE);
+ * SlashProcNet_FreeRoute6(rtArray);
  * @endcode
  *
  * @note        Caller is responsible for freeing the @c GPtrArray with
  *              SlashProcNet_FreeRoute6.
  * @note        This routine creates persistent GLib GRegexs.
  *
+ * @param[in]   maxRoutes       Max routes to gather.
+ * @param[in]   rtFilterFlags   Route flags used to filter out what we want.
+ *                              Set ~0 if want everything.
+ *
  * @return      On failure, NULL.  On success, a valid @c GPtrArray.
  * @todo        Consider init/cleanup routines to not "leak" GRegexs.
  * @todo        Consider rewriting, integrating with libdnet.
@@ -712,7 +733,8 @@ SlashProcNet_FreeRoute(GPtrArray *routeArray)
  */
 
 GPtrArray *
-SlashProcNet_GetRoute6(void)
+SlashProcNet_GetRoute6(unsigned int maxRoutes,
+                       unsigned int rtFilterFlags)
 {
    GIOChannel *myChannel = NULL;
    GIOStatus myIoStatus;
@@ -720,9 +742,12 @@ SlashProcNet_GetRoute6(void)
    gchar *myLine = NULL;
    Bool parseError = FALSE;
    int fd = -1;
+   unsigned int lineCount = 0;
 
    static GRegex *myValuesRE = NULL;
 
+   ASSERT(maxRoutes > 0);
+
    if (myValuesRE == NULL) {
       myValuesRE = g_regex_new("^([[:xdigit:]]{32}) ([[:xdigit:]]{2}) "
                                 "([[:xdigit:]]{32}) ([[:xdigit:]]{2}) "
@@ -738,7 +763,7 @@ SlashProcNet_GetRoute6(void)
     */
 
    if ((fd = g_open(pathToNetRoute6, O_RDONLY)) == -1) {
-      Warning("%s: open(%s): %s\n", __func__, pathToNetRoute,
+      Warning("%s: open(%s): %s\n", __func__, pathToNetRoute6,
               g_strerror(errno));
       return NULL;
    }
@@ -747,18 +772,18 @@ SlashProcNet_GetRoute6(void)
 
    myArray = g_ptr_array_new();
 
-   while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL,
-                                               NULL)) == G_IO_STATUS_NORMAL) {
+   while (lineCount < maxRoutes &&
+               (myIoStatus = g_io_channel_read_line(myChannel,
+                     &myLine, NULL, NULL, NULL)) == G_IO_STATUS_NORMAL) {
       struct in6_rtmsg *myEntry = NULL;
       GMatchInfo *myMatchInfo = NULL;
 
       if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) {
          parseError = TRUE;
-         goto badIteration;
+         goto iterationCleanup;
       }
 
       myEntry = g_new0(struct in6_rtmsg, 1);
-      g_ptr_array_add(myArray, myEntry);
 
       MATCHEXPR(myMatchInfo, 1, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_dst));
       MATCHEXPR(myMatchInfo, 3, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_src));
@@ -771,7 +796,15 @@ SlashProcNet_GetRoute6(void)
 
       MATCHEXPR(myMatchInfo, 8, myEntry->rtmsg_ifindex = if_nametoindex(MATCH));
 
-badIteration:
+      if (rtFilterFlags == (uint)~0 ||
+          (myEntry->rtmsg_flags & rtFilterFlags) != 0) {
+         g_ptr_array_add(myArray, myEntry);
+         lineCount++;
+      } else {
+         g_free(myEntry);
+      }
+
+iterationCleanup:
       g_free(myLine);
       myLine = NULL;
 
@@ -779,15 +812,15 @@ badIteration:
       myMatchInfo = NULL;
 
       if (parseError) {
+         /* Return NULL to signal parsing error */
+         if (myArray) {
+            SlashProcNet_FreeRoute6(myArray);
+            myArray = NULL;
+         }
          break;
       }
    }
 
-   if (myArray && myIoStatus != G_IO_STATUS_EOF) {
-      SlashProcNet_FreeRoute6(myArray);
-      myArray = NULL;
-   }
-
    g_free(myLine);
    myLine = NULL;
 
index 731b9b008d39eb51553b445522078517ce4c4275..5a13095bd4886d13e8365f203549308f5dfbcb85 100644 (file)
@@ -481,6 +481,8 @@ GuestInfoGather(gpointer data)
    ToolsAppCtx *ctx = data;
    Bool primaryChanged;
    Bool lowPriorityChanged;
+   int maxIPv4RoutesToGather;
+   int maxIPv6RoutesToGather;
 
    g_debug("Entered guest info gather.\n");
 
@@ -548,7 +550,42 @@ GuestInfoGather(gpointer data)
    lowPriorityChanged = GuestInfoResetNicLowPriorityList(ctx);
    GuestInfoResetNicExcludeList(ctx);
 
-   if (!GuestInfo_GetNicInfo(&nicInfo)) {
+   /*
+    * Check the config registry for max IPv4/6 routes to gather
+    */
+   maxIPv4RoutesToGather =
+         VMTools_ConfigGetInteger(ctx->config,
+                                  CONFGROUPNAME_GUESTINFO,
+                                  CONFNAME_GUESTINFO_MAXIPV4ROUTES,
+                                  NICINFO_MAX_ROUTES);
+   if (maxIPv4RoutesToGather < 0 ||
+       maxIPv4RoutesToGather > NICINFO_MAX_ROUTES) {
+      g_warning("Invalid %s.%s value: %d. Using default %u.\n",
+                CONFGROUPNAME_GUESTINFO,
+                CONFNAME_GUESTINFO_MAXIPV4ROUTES,
+                maxIPv4RoutesToGather,
+                NICINFO_MAX_ROUTES);
+      maxIPv4RoutesToGather = NICINFO_MAX_ROUTES;
+   }
+
+   maxIPv6RoutesToGather =
+         VMTools_ConfigGetInteger(ctx->config,
+                                  CONFGROUPNAME_GUESTINFO,
+                                  CONFNAME_GUESTINFO_MAXIPV6ROUTES,
+                                  NICINFO_MAX_ROUTES);
+   if (maxIPv6RoutesToGather < 0 ||
+       maxIPv6RoutesToGather > NICINFO_MAX_ROUTES) {
+      g_warning("Invalid %s.%s value: %d. Using default %u.\n",
+                CONFGROUPNAME_GUESTINFO,
+                CONFNAME_GUESTINFO_MAXIPV6ROUTES,
+                maxIPv6RoutesToGather,
+                NICINFO_MAX_ROUTES);
+      maxIPv6RoutesToGather = NICINFO_MAX_ROUTES;
+   }
+
+   if (!GuestInfo_GetNicInfo(maxIPv4RoutesToGather,
+                             maxIPv6RoutesToGather,
+                             &nicInfo)) {
       g_warning("Failed to get nic info.\n");
       /*
        * Return an empty nic info.
index aa5f2173bed476371cfadf26af41aa77ad8e1a22..6dfb843af0645bc7dde8b0fe8e3d11d61bbe68c6 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2015-2018 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -114,16 +114,58 @@ InfoUpdateNetwork(void)
    GuestNicProto msg = { 0 };
    GuestInfoType type = INFO_IPADDRESS_V3;
 
+   GKeyFile *confDict = NULL;
+   int maxIPv4RoutesToGather = NICINFO_MAX_ROUTES;
+   int maxIPv6RoutesToGather = NICINFO_MAX_ROUTES;
+
 #ifdef _WIN32
    DWORD dwRet = NetUtil_LoadIpHlpApiDll();
    if (dwRet != ERROR_SUCCESS) {
-      g_warning("NetUtil_LoadIpHlpApiDll() failed\n");
+      g_warning("NetUtil_LoadIpHlpApiDll() failed.\n");
       return EXIT_FAILURE;
    }
 #endif
 
-   if (!GuestInfo_GetNicInfo(&info)) {
-      g_warning("Failed to get nic info\n");
+   // Get the config options of max IPv4/IPv6 routes to gather
+   VMTools_LoadConfig(NULL, G_KEY_FILE_NONE, &confDict, NULL);
+
+   if (confDict != NULL) {
+      maxIPv4RoutesToGather =
+               VMTools_ConfigGetInteger(confDict,
+                                        CONFGROUPNAME_GUESTINFO,
+                                        CONFNAME_GUESTINFO_MAXIPV4ROUTES,
+                                        NICINFO_MAX_ROUTES);
+      if (maxIPv4RoutesToGather < 0 ||
+          maxIPv4RoutesToGather > NICINFO_MAX_ROUTES) {
+         g_warning("Invalid %s.%s value: %d. Using default %u.\n",
+                   CONFGROUPNAME_GUESTINFO,
+                   CONFNAME_GUESTINFO_MAXIPV4ROUTES,
+                   maxIPv4RoutesToGather,
+                   NICINFO_MAX_ROUTES);
+         maxIPv4RoutesToGather = NICINFO_MAX_ROUTES;
+      }
+
+      maxIPv6RoutesToGather =
+               VMTools_ConfigGetInteger(confDict,
+                                        CONFGROUPNAME_GUESTINFO,
+                                        CONFNAME_GUESTINFO_MAXIPV6ROUTES,
+                                        NICINFO_MAX_ROUTES);
+      if (maxIPv6RoutesToGather < 0 ||
+          maxIPv6RoutesToGather > NICINFO_MAX_ROUTES) {
+         g_warning("Invalid %s.%s value: %d. Using default %u.\n",
+                   CONFGROUPNAME_GUESTINFO,
+                   CONFNAME_GUESTINFO_MAXIPV6ROUTES,
+                   maxIPv6RoutesToGather,
+                   NICINFO_MAX_ROUTES);
+         maxIPv6RoutesToGather = NICINFO_MAX_ROUTES;
+      }
+      g_key_file_free(confDict);
+   }
+
+   if (!GuestInfo_GetNicInfo(maxIPv4RoutesToGather,
+                             maxIPv6RoutesToGather,
+                             &info)) {
+      g_warning("Failed to get nic info.\n");
       ret = EXIT_FAILURE;
       goto done;
    }