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
This commit is contained in:
Mark Johnston 2019-04-30 14:44:39 +00:00
parent cbc5290710
commit 180d54d009

View File

@ -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 ifindex)
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;