The following diff adds support for detecting the state change of a departed
interface. ifstated is not a very verbose daemon, so this diff quietly does
the right thing (i.e. there is no exttra warning about a departing interface).

The re-arrival of a departed interface involves re-indexing the interface and
possibly other complexities that require more consideration, but for now at
least this obvious condition is handled in what I believe is a more
appropriate manner.

Updated regression tests pass, and the corresponding regression diff is also
attached.

Ok?

Index: regress/usr.sbin/ifstated/ifstated
===================================================================
RCS file: /cvs/src/regress/usr.sbin/ifstated/ifstated,v
retrieving revision 1.3
diff -u -p -r1.3 ifstated
--- regress/usr.sbin/ifstated/ifstated  31 Jul 2017 18:41:21 -0000      1.3
+++ regress/usr.sbin/ifstated/ifstated  6 Aug 2017 23:29:11 -0000
@@ -124,6 +124,7 @@ changing state to primary
 changing state to demoted
 changing state to primary
 changing state to primary
+changing state to demoted
 EOF
 
 (cd working && nohup ifstated -dvf ./ifstated.conf > ifstated.log 2>&1) &
@@ -148,6 +149,8 @@ ifconfig carp${VHIDB} inet ${PREFIX}.${V
    ${PREFIX}.255 vhid ${VHIDB} carpdev ${NIC}
 sleep ${SLEEP}
 kill -HUP $(pgrep ifstated) >/dev/null 2>&1
+sleep ${SLEEP}
+ifconfig carp${VHIDA} destroy
 sleep ${SLEEP}
 
 grep ^changing working/ifstated.log > working/output.new
Index: usr.sbin/ifstated/ifstated.c
===================================================================
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.57
diff -u -p -r1.57 ifstated.c
--- usr.sbin/ifstated/ifstated.c        6 Aug 2017 19:27:54 -0000       1.57
+++ usr.sbin/ifstated/ifstated.c        6 Aug 2017 23:29:12 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ifstated.c,v 1.57 2017/08/06 19:27:54 rob Exp $       */
+/*     $OpenBSD: ifstated.c,v 1.56 2017/07/24 12:33:59 jca Exp $       */
 
 /*
  * Copyright (c) 2004 Marco Pfatschbacher <m...@openbsd.org>
@@ -61,6 +61,7 @@ void          rt_msg_handler(int, short, void *)
 void           external_handler(int, short, void *);
 void           external_exec(struct ifsd_external *, int);
 void           check_external_status(struct ifsd_state *);
+void           check_for_ifdeparture(void);
 void           external_evtimer_setup(struct ifsd_state *, int);
 void           scan_ifstate(int, int, int);
 int            scan_ifstate_single(int, int, struct ifsd_state *);
@@ -150,7 +151,7 @@ main(int argc, char *argv[])
        if ((rt_fd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
                err(1, "no routing socket");
 
-       rtfilter = ROUTE_FILTER(RTM_IFINFO);
+       rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_IFANNOUNCE);
        if (setsockopt(rt_fd, PF_ROUTE, ROUTE_MSGFILTER,
            &rtfilter, sizeof(rtfilter)) == -1) /* not fatal */
                log_warn("%s: setsockopt msgfilter", __func__);
@@ -234,6 +235,7 @@ rt_msg_handler(int fd, short event, void
        char msg[2048];
        struct rt_msghdr *rtm = (struct rt_msghdr *)&msg;
        struct if_msghdr ifm;
+       struct if_announcemsghdr ifan;
        ssize_t len;
 
        if ((len = read(fd, msg, sizeof(msg))) == -1) {
@@ -253,8 +255,19 @@ rt_msg_handler(int fd, short event, void
                memcpy(&ifm, rtm, sizeof(ifm));
                scan_ifstate(ifm.ifm_index, ifm.ifm_data.ifi_link_state, 1);
                break;
+       case RTM_IFANNOUNCE:
+               memcpy(&ifan, rtm, sizeof(ifan));
+               switch (ifan.ifan_what) {
+               case IFAN_DEPARTURE:
+                       scan_ifstate(ifan.ifan_index, LINK_STATE_DOWN, 1);
+                       break;
+               default:
+                       break;
+               }
+               break;
        case RTM_DESYNC:
                fetch_ifstate(1);
+               check_for_ifdeparture();
                break;
        default:
                break;
@@ -626,6 +639,26 @@ fetch_ifstate(int do_eval)
        }
 
        freeifaddrs(ifap);
+}
+
+void
+check_for_ifdeparture(void)
+{
+       struct ifsd_state *state;
+       struct ifsd_ifstate *ifstate;
+       char ifnamebuf[IF_NAMESIZE];
+       char *if_name;
+
+       TAILQ_FOREACH(state, &conf->states, entries) {
+               TAILQ_FOREACH(ifstate, &state->interface_states, entries) {
+                       if_name = if_indextoname(ifstate->ifindex, ifnamebuf);
+                       if (if_name == NULL) {
+                               scan_ifstate(ifstate->ifindex,
+                                  LINK_STATE_DOWN, 1);
+                       }
+               }
+       }
+       return;
 }
 
 void

Reply via email to