From: Oliver Kurth Date: Tue, 19 Jun 2018 18:07:44 +0000 (-0700) Subject: Add two switches for max IPv4/6 routes to gather X-Git-Tag: stable-10.3.0~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=065f09b94e09f1127901db29e73cc9b9f36df4fc;p=thirdparty%2Fopen-vm-tools.git Add two switches for max IPv4/6 routes to gather 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. --- diff --git a/open-vm-tools/lib/include/conf.h b/open-vm-tools/lib/include/conf.h index 185e89bcf..af6853487 100644 --- a/open-vm-tools/lib/include/conf.h +++ b/open-vm-tools/lib/include/conf.h @@ -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 @@ -134,6 +134,28 @@ #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. * diff --git a/open-vm-tools/lib/include/nicInfo.h b/open-vm-tools/lib/include/nicInfo.h index 5f26ddec0..59b28b851 100644 --- a/open-vm-tools/lib/include/nicInfo.h +++ b/open-vm-tools/lib/include/nicInfo.h @@ -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); diff --git a/open-vm-tools/lib/include/slashProc.h b/open-vm-tools/lib/include/slashProc.h index e6c8dcdb5..c5d9b40e0 100644 --- a/open-vm-tools/lib/include/slashProc.h +++ b/open-vm-tools/lib/include/slashProc.h @@ -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 @@ -35,10 +35,10 @@ 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_ diff --git a/open-vm-tools/lib/nicInfo/nicInfo.c b/open-vm-tools/lib/nicInfo/nicInfo.c index 7ec8320fe..ce9ebae38 100644 --- a/open-vm-tools/lib/nicInfo/nicInfo.c +++ b/open-vm-tools/lib/nicInfo/nicInfo.c @@ -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; diff --git a/open-vm-tools/lib/nicInfo/nicInfoInt.h b/open-vm-tools/lib/nicInfo/nicInfoInt.h index 4afe58166..1fac8024c 100644 --- a/open-vm-tools/lib/nicInfo/nicInfoInt.h +++ b/open-vm-tools/lib/nicInfo/nicInfoInt.h @@ -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 diff --git a/open-vm-tools/lib/nicInfo/nicInfoPosix.c b/open-vm-tools/lib/nicInfo/nicInfoPosix.c index 818e61e72..8a063a080 100644 --- a/open-vm-tools/lib/nicInfo/nicInfoPosix.c +++ b/open-vm-tools/lib/nicInfo/nicInfoPosix.c @@ -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; } diff --git a/open-vm-tools/lib/slashProc/net.c b/open-vm-tools/lib/slashProc/net.c index 1d2a88800..82b69638f 100644 --- a/open-vm-tools/lib/slashProc/net.c +++ b/open-vm-tools/lib/slashProc/net.c @@ -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 - * struct rtentrys. + * @brief Reads the first @c maxRoutes lines of @ref pathToNetRoute and + * returns a @c GPtrArray of struct rtentrys. * * 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 - * struct in6_rtmsgs. + * @brief Reads the first @c maxRoutes lines of @ref pathToNetRoute6 and + * returns a @c GPtrArray of struct in6_rtmsgs. * * 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; diff --git a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c index 731b9b008..5a13095bd 100644 --- a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c +++ b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c @@ -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. diff --git a/open-vm-tools/toolbox/toolboxcmd-info.c b/open-vm-tools/toolbox/toolboxcmd-info.c index aa5f2173b..6dfb843af 100644 --- a/open-vm-tools/toolbox/toolboxcmd-info.c +++ b/open-vm-tools/toolbox/toolboxcmd-info.c @@ -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; }