this makes carp less special by having it register detachhooks. right now if.c treats it better than it needs to.
the diff shuffles establishment of the link status hook and the new detachhook to make carp_set_ifp fail if the hooks cannot be allocated. the following seems to work both before and after the diff: ifconfig vether1 create ifconfig -g carp carpdemote 20 ifconfig carp0 create ifconfig carp0 carpdev vether1 ifconfig carp0 vhid 66 ifconfig carp0 pass `openssl rand -base64 12` ifconfig carp0 advskew 192 ifconfig carp0 inet alias 100.64.0.1 netmask 255.255.255.0 ifconfig vether1 ifconfig carp0 ifconfig vether1 destroy ifconfig carp0 tests? Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.537 diff -u -p -r1.537 if.c --- net/if.c 10 Jan 2018 23:50:39 -0000 1.537 +++ net/if.c 12 Jan 2018 01:50:44 -0000 @@ -1005,11 +1005,6 @@ if_deactivate(struct ifnet *ifp) */ dohooks(ifp->if_detachhooks, HOOK_REMOVE | HOOK_FREE); -#if NCARP > 0 - /* Remove the interface from any carp group it is a part of. */ - if (ifp->if_type != IFT_CARP && !SRPL_EMPTY_LOCKED(&ifp->if_carp)) - carp_ifdetach(ifp); -#endif NET_UNLOCK(); } Index: netinet/ip_carp.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_carp.c,v retrieving revision 1.325 diff -u -p -r1.325 ip_carp.c --- netinet/ip_carp.c 12 Jan 2018 00:36:13 -0000 1.325 +++ netinet/ip_carp.c 12 Jan 2018 01:50:44 -0000 @@ -133,6 +133,7 @@ struct carp_softc { #define sc_carpdev sc_ac.ac_if.if_carpdev void *ah_cookie; void *lh_cookie; + void *dh_cookie; struct ip_moptions sc_imo; #ifdef INET6 struct ip6_moptions sc_im6o; @@ -215,7 +216,7 @@ int carp_proto_input_if(struct ifnet *, int carp6_proto_input_if(struct ifnet *, struct mbuf **, int *, int); #endif void carpattach(int); -void carpdetach(struct carp_softc *); +void carpdetach(void *); int carp_prepare_ad(struct mbuf *, struct carp_vhost_entry *, struct carp_header *); void carp_send_ad_all(void); @@ -901,8 +902,9 @@ carp_del_all_timeouts(struct carp_softc } void -carpdetach(struct carp_softc *sc) +carpdetach(void *arg) { + struct carp_softc *sc = arg; struct ifnet *ifp0; struct srpl *cif; @@ -929,26 +931,13 @@ carpdetach(struct carp_softc *sc) /* Restore previous input handler. */ if_ih_remove(ifp0, carp_input, NULL); - if (sc->lh_cookie != NULL) - hook_disestablish(ifp0->if_linkstatehooks, sc->lh_cookie); - SRPL_REMOVE_LOCKED(&carp_sc_rc, cif, sc, carp_softc, sc_list); if (SRPL_EMPTY_LOCKED(cif)) ifpromisc(ifp0, 0); sc->sc_carpdev = NULL; -} - -/* Detach an interface from the carp. */ -void -carp_ifdetach(struct ifnet *ifp0) -{ - struct carp_softc *sc, *nextsc; - struct srpl *cif = &ifp0->if_carp; - KERNEL_ASSERT_LOCKED(); /* touching if_carp */ - - SRPL_FOREACH_SAFE_LOCKED(sc, cif, sc_list, nextsc) - carpdetach(sc); + hook_disestablish(ifp0->if_linkstatehooks, sc->lh_cookie); + hook_disestablish(ifp0->if_detachhooks, sc->dh_cookie); } void @@ -1697,13 +1686,27 @@ carp_set_ifp(struct carp_softc *sc, stru if (ifp0->if_type != IFT_ETHER) return (EINVAL); + sc->dh_cookie = hook_establish(ifp0->if_detachhooks, 0, + carpdetach, sc); + if (sc->dh_cookie == NULL) + return (ENOMEM); + + sc->lh_cookie = hook_establish(ifp0->if_linkstatehooks, 1, + carp_carpdev_state, ifp0); + if (sc->lh_cookie == NULL) { + error = ENOMEM; + goto rm_dh; + } + cif = &ifp0->if_carp; if (SRPL_EMPTY_LOCKED(cif)) { if ((error = ifpromisc(ifp0, 1))) - return (error); + goto rm_lh; - } else if (carp_check_dup_vhids(sc, cif, NULL)) - return (EINVAL); + } else if (carp_check_dup_vhids(sc, cif, NULL)) { + error = EINVAL; + goto rm_lh; + } /* detach from old interface */ if (sc->sc_carpdev != NULL) @@ -1744,15 +1747,19 @@ carp_set_ifp(struct carp_softc *sc, stru sc->sc_if.if_flags |= IFF_UP; carp_set_enaddr(sc); - sc->lh_cookie = hook_establish(ifp0->if_linkstatehooks, 1, - carp_carpdev_state, ifp0); - /* Change input handler of the physical interface. */ if_ih_insert(ifp0, carp_input, NULL); carp_carpdev_state(ifp0); return (0); + +rm_lh: + hook_disestablish(ifp0->if_linkstatehooks, sc->lh_cookie); +rm_dh: + hook_disestablish(ifp0->if_detachhooks, sc->dh_cookie); + + return (error); } void Index: netinet/ip_carp.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_carp.h,v retrieving revision 1.45 diff -u -p -r1.45 ip_carp.h --- netinet/ip_carp.h 10 Jan 2018 23:50:39 -0000 1.45 +++ netinet/ip_carp.h 12 Jan 2018 01:50:44 -0000 @@ -193,7 +193,6 @@ carpstat_inc(enum carpstat_counters c) counters_inc(carpcounters, c); } -void carp_ifdetach (struct ifnet *); int carp_proto_input(struct mbuf **, int *, int, int); void carp_carpdev_state(void *); void carp_group_demote_adj(struct ifnet *, int, char *);