ifwatchd: Enable SO_RERROR to re-sync interface state.

Interface arrival, departure and link state changes will sync
and if different will be actioned.

Currently we do not track addresses, so any changes there are still lost.
This commit is contained in:
roy 2020-10-04 20:36:32 +00:00
parent 5b432bdbfd
commit 82328146fe
1 changed files with 73 additions and 27 deletions

View File

@ -1,6 +1,6 @@
/* $NetBSD: ifwatchd.c,v 1.45 2020/09/27 19:55:21 roy Exp $ */
/* $NetBSD: ifwatchd.c,v 1.46 2020/10/04 20:36:32 roy Exp $ */
#include <sys/cdefs.h>
__RCSID("$NetBSD: ifwatchd.c,v 1.45 2020/09/27 19:55:21 roy Exp $");
__RCSID("$NetBSD: ifwatchd.c,v 1.46 2020/10/04 20:36:32 roy Exp $");
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -44,15 +44,16 @@ __RCSID("$NetBSD: ifwatchd.c,v 1.45 2020/09/27 19:55:21 roy Exp $");
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <err.h>
#include <ifaddrs.h>
#include <syslog.h>
#include <unistd.h>
enum event { ARRIVAL, DEPARTURE, UP, DOWN, CARRIER, NO_CARRIER };
enum addrflag { NOTREADY, DETACHED, READY };
@ -69,7 +70,7 @@ static void check_announce(const struct if_announcemsghdr *ifan);
static void check_carrier(const struct if_msghdr *ifm);
static void free_interfaces(void);
static struct interface_data * find_interface(int index);
static void run_initial_ups(void);
static void run_initial_ups(bool);
/* global variables */
static int verbose = 0, quiet = 0;
@ -197,9 +198,12 @@ main(int argc, char **argv)
if (setsockopt(s, PF_ROUTE, RO_MSGFILTER,
&msgfilter, sizeof(msgfilter)) < 0)
syslog(LOG_ERR, "RO_MSGFILTER: %m");
n = 1;
if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) < 0)
syslog(LOG_ERR, "SO_RERROR: %m");
if (!inhibit_initial)
run_initial_ups();
run_initial_ups(true);
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
@ -210,6 +214,15 @@ main(int argc, char **argv)
for (;;) {
n = recvmsg(s, &msg, 0);
if (n == -1) {
if (errno == ENOBUFS) {
syslog(LOG_ERR,
"routing socket overflow detected");
/* XXX We don't track addresses, so they
* won't be reported. */
if (!inhibit_initial)
run_initial_ups(false);
continue;
}
syslog(LOG_ERR, "recvmsg: %m");
exit(EXIT_FAILURE);
}
@ -481,6 +494,28 @@ check_carrier(const struct if_msghdr *ifm)
}
}
static void
do_announce(struct interface_data *ifd,
unsigned short what, unsigned short index)
{
switch (what) {
case IFAN_ARRIVAL:
ifd->index = index;
invoke_script(ifd->ifname, ARRIVAL, NULL, NULL);
break;
case IFAN_DEPARTURE:
ifd->index = -1;
ifd->last_carrier_status = -1;
invoke_script(ifd->ifname, DEPARTURE, NULL, NULL);
break;
default:
if (verbose)
(void) printf("unknown announce: what=%d\n", what);
break;
}
}
static void
check_announce(const struct if_announcemsghdr *ifan)
{
@ -491,22 +526,7 @@ check_announce(const struct if_announcemsghdr *ifan)
if (strcmp(p->ifname, ifname) != 0)
continue;
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
p->index = ifan->ifan_index;
invoke_script(p->ifname, ARRIVAL, NULL, NULL);
break;
case IFAN_DEPARTURE:
p->index = -1;
p->last_carrier_status = -1;
invoke_script(p->ifname, DEPARTURE, NULL, NULL);
break;
default:
if (verbose)
(void) printf("unknown announce: "
"what=%d\n", ifan->ifan_what);
break;
}
do_announce(p, ifan->ifan_what, ifan->ifan_index);
return;
}
}
@ -536,7 +556,7 @@ find_interface(int idx)
}
static void
run_initial_ups(void)
run_initial_ups(bool do_addrs)
{
struct interface_data * ifd;
struct ifaddrs *res = NULL, *p;
@ -551,6 +571,19 @@ run_initial_ups(void)
if (getifaddrs(&res) != 0)
goto out;
/* Check if any interfaces vanished */
SLIST_FOREACH(ifd, &ifs, next) {
for (p = res; p; p = p->ifa_next) {
if (strcmp(ifd->ifname, p->ifa_name) != 0)
continue;
ifa = p->ifa_addr;
if (ifa != NULL && ifa->sa_family == AF_LINK)
break;
}
if (p == NULL)
do_announce(ifd, IFAN_DEPARTURE, ifd->index);
}
for (p = res; p; p = p->ifa_next) {
SLIST_FOREACH(ifd, &ifs, next) {
if (strcmp(ifd->ifname, p->ifa_name) == 0)
@ -560,7 +593,8 @@ run_initial_ups(void)
continue;
ifa = p->ifa_addr;
if (ifa != NULL && ifa->sa_family == AF_LINK)
if (ifa != NULL && ifa->sa_family == AF_LINK &&
ifd->index == -1)
invoke_script(ifd->ifname, ARRIVAL, NULL, NULL);
if ((p->ifa_flags & IFF_UP) == 0)
@ -569,11 +603,23 @@ run_initial_ups(void)
continue;
if (ifa->sa_family == AF_LINK) {
ifi = (const struct if_data *)p->ifa_data;
if (ifi->ifi_link_state == LINK_STATE_UP)
if (ifd->last_carrier_status == ifi->ifi_link_state)
continue;
switch (ifi->ifi_link_state) {
case LINK_STATE_UP:
invoke_script(ifd->ifname, CARRIER, NULL, NULL);
break;
case LINK_STATE_DOWN:
if (ifd->last_carrier_status == -1)
break;
invoke_script(ifd->ifname, CARRIER, NULL, NULL);
break;
}
ifd->last_carrier_status = ifi->ifi_link_state;
continue;
}
if (!do_addrs)
continue;
aflag = check_addrflags(ifa->sa_family, p->ifa_addrflags);
if (aflag != READY)
continue;