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:
parent
cbc5290710
commit
180d54d009
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user