summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_carp.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2006-03-21 14:29:48 +0000
committerglebius <glebius@FreeBSD.org>2006-03-21 14:29:48 +0000
commitaca7253de4a59d55274c156cecd37c9417107154 (patch)
treedfd6904f3d5a3132f478ea4e967cb3d3c2e0f6a3 /sys/netinet/ip_carp.c
parent53d6233f744cffc5f29606f3a746783c571f7766 (diff)
downloadFreeBSD-src-aca7253de4a59d55274c156cecd37c9417107154.zip
FreeBSD-src-aca7253de4a59d55274c156cecd37c9417107154.tar.gz
o Introduce carp_multicast_cleanup(), which removes and frees
multicast addresses from carp interface. [1] o Rewrite carpdetach(), so that it does the following things: [1] - Stops callouts. - Decrements carp_suppress_preempt, if needed. - Downs interface and sets CARP state to INIT. - Calls carp_multicast_cleanup(). - Detaches softc from carp_if and if we are the last frees the carp_if. o Use new carpdetach() in carp_clone_destroy(). o In carp_ifdetach() acquire the carp_if lock and cleanup all interfaces hanging on carp_if. [1] o Make carp_ifdetach() static and use EVENT(9) to call it from if_detach(). [2] o In carp_setrun() exit if the softc doesn't have a valid pointer to parent. [1] Obtained from: OpenBSD [1] Submitted by: Dan Lukes <dan obluda.cz> [2] PR: kern/82908 [2]
Diffstat (limited to 'sys/netinet/ip_carp.c')
-rw-r--r--sys/netinet/ip_carp.c185
1 files changed, 101 insertions, 84 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 048dad5..5c7c00b 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -209,6 +209,7 @@ static void carp_set_state(struct carp_softc *, int);
static int carp_addrcount(struct carp_if *, struct in_ifaddr *, int);
enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING };
+static void carp_multicast_cleanup(struct carp_softc *);
static int carp_set_addr(struct carp_softc *, struct sockaddr_in *);
static int carp_del_addr(struct carp_softc *, struct sockaddr_in *);
static void carp_carpdev_state_locked(struct carp_if *);
@@ -223,6 +224,8 @@ static LIST_HEAD(, carp_softc) carpif_list;
static struct mtx carp_mtx;
IFC_SIMPLE_DECLARE(carp, 0);
+static eventhandler_tag if_detach_event_tag;
+
static __inline u_int16_t
carp_cksum(struct mbuf *m, int len)
{
@@ -399,63 +402,76 @@ static void
carp_clone_destroy(struct ifnet *ifp)
{
struct carp_softc *sc = ifp->if_softc;
+
+ if (sc->sc_carpdev)
+ CARP_SCLOCK(sc);
+ carpdetach(sc);
+ if (sc->sc_carpdev)
+ CARP_SCUNLOCK(sc);
+
+ mtx_lock(&carp_mtx);
+ LIST_REMOVE(sc, sc_next);
+ mtx_unlock(&carp_mtx);
+ bpfdetach(ifp);
+ if_detach(ifp);
+ if_free_type(ifp, IFT_ETHER);
+ free(sc, M_CARP);
+}
+
+static void
+carpdetach(struct carp_softc *sc)
+{
struct carp_if *cif;
- struct ip_moptions *imo = &sc->sc_imo;
-#ifdef INET6
- struct ip6_moptions *im6o = &sc->sc_im6o;
-#endif
-
-/* carpdetach(sc); */
- /*
- * If an interface is destroyed which is suppressing the preemption,
- * decrease the global counter, otherwise the host will never get
- * out of the carp supressing state.
- */
+ callout_stop(&sc->sc_ad_tmo);
+ callout_stop(&sc->sc_md_tmo);
+ callout_stop(&sc->sc_md6_tmo);
+
if (sc->sc_suppress)
carp_suppress_preempt--;
sc->sc_suppress = 0;
- callout_stop(&sc->sc_ad_tmo);
- callout_stop(&sc->sc_md_tmo);
- callout_stop(&sc->sc_md6_tmo);
+ if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS)
+ carp_suppress_preempt--;
+ sc->sc_sendad_errors = 0;
- if (imo->imo_num_memberships) {
- in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
- imo->imo_multicast_ifp = NULL;
- }
-#ifdef INET6
- while (!LIST_EMPTY(&im6o->im6o_memberships)) {
- struct in6_multi_mship *imm =
- LIST_FIRST(&im6o->im6o_memberships);
- LIST_REMOVE(imm, i6mm_chain);
- in6_leavegroup(imm);
- }
- im6o->im6o_multicast_ifp = NULL;
-#endif
+ carp_set_state(sc, INIT);
+ SC2IFP(sc)->if_flags &= ~IFF_UP;
+ carp_setrun(sc, 0);
+ carp_multicast_cleanup(sc);
- /* Remove ourself from parents if_carp queue */
- if (sc->sc_carpdev && (cif = sc->sc_carpdev->if_carp)) {
- CARP_LOCK(cif);
+ if (sc->sc_carpdev != NULL) {
+ cif = (struct carp_if *)sc->sc_carpdev->if_carp;
+ CARP_LOCK_ASSERT(cif);
TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
if (!--cif->vhif_nvrs) {
+ ifpromisc(sc->sc_carpdev, 0);
sc->sc_carpdev->if_carp = NULL;
CARP_LOCK_DESTROY(cif);
- FREE(cif, M_CARP);
- ifpromisc(sc->sc_carpdev, 0);
- sc->sc_carpdev = NULL;
- } else {
- CARP_UNLOCK(cif);
+ FREE(cif, M_IFADDR);
}
}
+ sc->sc_carpdev = NULL;
+}
- mtx_lock(&carp_mtx);
- LIST_REMOVE(sc, sc_next);
- mtx_unlock(&carp_mtx);
- bpfdetach(ifp);
- if_detach(ifp);
- if_free_type(ifp, IFT_ETHER);
- free(sc, M_CARP);
+/* Detach an interface from the carp. */
+static void
+carp_ifdetach(void *arg __unused, struct ifnet *ifp)
+{
+ struct carp_if *cif = (struct carp_if *)ifp->if_carp;
+ struct carp_softc *sc, *nextsc;
+
+ if (cif == NULL)
+ return;
+
+ /*
+ * XXX: At the end of for() cycle the lock will be destroyed.
+ */
+ CARP_LOCK(cif);
+ for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) {
+ nextsc = TAILQ_NEXT(sc, sc_list);
+ carpdetach(sc);
+ }
}
/*
@@ -751,42 +767,6 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
return;
}
-static void
-carpdetach(struct carp_softc *sc)
-{
- struct ifaddr *ifa;
-
- callout_stop(&sc->sc_ad_tmo);
- callout_stop(&sc->sc_md_tmo);
- callout_stop(&sc->sc_md6_tmo);
-
- while ((ifa = TAILQ_FIRST(&SC2IFP(sc)->if_addrlist)) != NULL)
- if (ifa->ifa_addr->sa_family == AF_INET) {
- struct in_ifaddr *ia = ifatoia(ifa);
-
- carp_del_addr(sc, &ia->ia_addr);
-
- /* ripped screaming from in_control(SIOCDIFADDR) */
- in_ifscrub(SC2IFP(sc), ia);
- TAILQ_REMOVE(&SC2IFP(sc)->if_addrlist, ifa, ifa_link);
- TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
- IFAFREE((&ia->ia_ifa));
- }
-}
-
-/* Detach an interface from the carp. */
-void
-carp_ifdetach(struct ifnet *ifp)
-{
- struct carp_softc *sc;
- struct carp_if *cif = (struct carp_if *)ifp->if_carp;
-
- CARP_LOCK(cif);
- TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list)
- carpdetach(sc);
- CARP_UNLOCK(cif);
-}
-
static int
carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch)
{
@@ -1307,7 +1287,11 @@ carp_setrun(struct carp_softc *sc, sa_family_t af)
{
struct timeval tv;
- if (sc->sc_carpdev)
+ if (sc->sc_carpdev == NULL) {
+ SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
+ carp_set_state(sc, INIT);
+ return;
+ } else
CARP_SCLOCK_ASSERT(sc);
if (SC2IFP(sc)->if_flags & IFF_UP &&
@@ -1374,6 +1358,37 @@ carp_setrun(struct carp_softc *sc, sa_family_t af)
}
}
+void
+carp_multicast_cleanup(struct carp_softc *sc)
+{
+ struct ip_moptions *imo = &sc->sc_imo;
+#ifdef INET6
+ struct ip6_moptions *im6o = &sc->sc_im6o;
+#endif
+ u_int16_t n = imo->imo_num_memberships;
+
+ /* Clean up our own multicast memberships */
+ while (n-- > 0) {
+ if (imo->imo_membership[n] != NULL) {
+ in_delmulti(imo->imo_membership[n]);
+ imo->imo_membership[n] = NULL;
+ }
+ }
+ imo->imo_num_memberships = 0;
+ imo->imo_multicast_ifp = NULL;
+
+#ifdef INET6
+ while (!LIST_EMPTY(&im6o->im6o_memberships)) {
+ struct in6_multi_mship *imm =
+ LIST_FIRST(&im6o->im6o_memberships);
+
+ LIST_REMOVE(imm, i6mm_chain);
+ in6_leavegroup(imm);
+ }
+ im6o->im6o_multicast_ifp = NULL;
+#endif
+}
+
static int
carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
{
@@ -2134,26 +2149,28 @@ carp_sc_state_locked(struct carp_softc *sc)
static int
carp_modevent(module_t mod, int type, void *data)
{
- int error = 0;
-
switch (type) {
case MOD_LOAD:
+ if_detach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ carp_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
+ if (if_detach_event_tag == NULL)
+ return (ENOMEM);
mtx_init(&carp_mtx, "carp_mtx", NULL, MTX_DEF);
LIST_INIT(&carpif_list);
if_clone_attach(&carp_cloner);
break;
case MOD_UNLOAD:
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag);
if_clone_detach(&carp_cloner);
mtx_destroy(&carp_mtx);
break;
default:
- error = EINVAL;
- break;
+ return (EINVAL);
}
- return error;
+ return (0);
}
static moduledata_t carp_mod = {
OpenPOWER on IntegriCloud