Date: Tue, 30 Apr 2019 14:44:40 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r346960 - head/usr.sbin/rtadvd Message-ID: <201904301444.x3UEieAU088107@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markj Date: Tue Apr 30 14:44:39 2019 New Revision: 346960 URL: https://svnweb.freebsd.org/changeset/base/346960 Log: Retry upon NET_RT_IFLIST sysctl failure. Port the logic used by getifaddrs(3) to handle the case where NET_RT_IFLIST returns ENOMEM, which can occur if the list size changes between the buffer allocation and sysctl read. PR: 195191 Submitted by: Guy Yur <guyyur@gmail.com> (original version) MFC after: 1 week Modified: head/usr.sbin/rtadvd/if.c Modified: head/usr.sbin/rtadvd/if.c ============================================================================== --- head/usr.sbin/rtadvd/if.c Tue Apr 30 14:29:09 2019 (r346959) +++ head/usr.sbin/rtadvd/if.c Tue Apr 30 14:44:39 2019 (r346960) @@ -408,6 +408,8 @@ update_ifinfo_nd_flags(struct ifinfo *ifi) return (0); } +#define MAX_SYSCTL_TRY 5 + struct ifinfo * update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex) { @@ -419,26 +421,43 @@ update_ifinfo(struct ifilist_head_t *ifi_head, int ifi size_t len; char *lim; int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 }; - int error; + int error, ntry; syslog(LOG_DEBUG, "<%s> enter", __func__); - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) < - 0) { - syslog(LOG_ERR, - "<%s> sysctl: NET_RT_IFLIST size get failed", __func__); - exit(1); - } - if ((msg = malloc(len)) == NULL) { - syslog(LOG_ERR, "<%s> malloc failed", __func__); - exit(1); - } - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) < - 0) { - syslog(LOG_ERR, - "<%s> sysctl: NET_RT_IFLIST get failed", __func__); - exit(1); - } + ntry = 0; + do { + /* + * We'll try to get addresses several times in case that + * the number of addresses is unexpectedly increased during + * the two sysctl calls. This should rarely happen. + * Portability note: since FreeBSD does not add margin of + * memory at the first sysctl, the possibility of failure on + * the second sysctl call is a bit higher. + */ + + if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) { + syslog(LOG_ERR, + "<%s> sysctl: NET_RT_IFLIST size get failed", + __func__); + exit(1); + } + if ((msg = malloc(len)) == NULL) { + syslog(LOG_ERR, "<%s> malloc failed", __func__); + exit(1); + } + if (sysctl(mib, nitems(mib), msg, &len, NULL, 0) < 0) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + free(msg); + syslog(LOG_ERR, + "<%s> sysctl: NET_RT_IFLIST get failed", + __func__); + exit(1); + } + free(msg); + msg = NULL; + } + } while (msg == NULL); lim = msg + len; for (ifm = (struct if_msghdr *)msg;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904301444.x3UEieAU088107>