diff options
Diffstat (limited to 'freebsd/sys/netinet/ip_carp.c')
-rw-r--r-- | freebsd/sys/netinet/ip_carp.c | 137 |
1 files changed, 63 insertions, 74 deletions
diff --git a/freebsd/sys/netinet/ip_carp.c b/freebsd/sys/netinet/ip_carp.c index 1fb208a2..03ce7bbe 100644 --- a/freebsd/sys/netinet/ip_carp.c +++ b/freebsd/sys/netinet/ip_carp.c @@ -646,6 +646,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) struct carp_softc *sc; uint64_t tmp_counter; struct timeval sc_tv, ch_tv; + struct epoch_tracker et; int error; /* @@ -659,7 +660,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) * (these should never happen, and as noted above, we may * miss real loops; this is just a double-check). */ - IF_ADDR_RLOCK(ifp); + NET_EPOCH_ENTER(et); error = 0; match = NULL; IFNET_FOREACH_IFA(ifp, ifa) { @@ -673,7 +674,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) ifa = error ? NULL : match; if (ifa != NULL) ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); if (ifa == NULL) { if (error == ELOOP) { @@ -881,18 +882,19 @@ carp_send_ad_error(struct carp_softc *sc, int error) static struct ifaddr * carp_best_ifa(int af, struct ifnet *ifp) { + struct epoch_tracker et; struct ifaddr *ifa, *best; if (af >= AF_MAX) return (NULL); best = NULL; - IF_ADDR_RLOCK(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == af && (best == NULL || ifa_preferred(best, ifa))) best = ifa; } - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); if (best != NULL) ifa_ref(best); return (best); @@ -1169,10 +1171,11 @@ carp_send_na(struct carp_softc *sc) struct ifaddr * carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) { + struct epoch_tracker et; struct ifaddr *ifa; ifa = NULL; - IF_ADDR_RLOCK(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1184,7 +1187,7 @@ carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) ifa_ref(ifa); break; } - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return (ifa); } @@ -1192,16 +1195,17 @@ carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) caddr_t carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) { + struct epoch_tracker et; struct ifaddr *ifa; - IF_ADDR_RLOCK(ifp); + NET_EPOCH_ENTER(et); IFNET_FOREACH_IFA(ifp, ifa) if (ifa->ifa_addr->sa_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(taddr, IFA_IN6(ifa))) { struct carp_softc *sc = ifa->ifa_carp; struct m_tag *mtag; - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); mtag = m_tag_get(PACKET_TAG_CARP, sizeof(struct carp_softc *), M_NOWAIT); @@ -1214,7 +1218,7 @@ carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) return (LLADDR(&sc->sc_addr)); } - IF_ADDR_RUNLOCK(ifp); + NET_EPOCH_EXIT(et); return (NULL); } @@ -1369,25 +1373,24 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET: { struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; struct in_addr addr; - if (imo->imo_membership) + if (ip_mfilter_first(&imo->imo_head) != NULL) return (0); - imo->imo_membership = (struct in_multi **)malloc( - (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, - M_WAITOK); - imo->imo_mfilters = NULL; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; + imf = ip_mfilter_alloc(M_WAITOK, 0, 0); + ip_mfilter_init(&imo->imo_head); imo->imo_multicast_vif = -1; addr.s_addr = htonl(INADDR_CARP_GROUP); if ((error = in_joingroup(ifp, &addr, NULL, - &imo->imo_membership[0])) != 0) { - free(imo->imo_membership, M_CARP); + &imf->imf_inm)) != 0) { + ip_mfilter_free(imf); break; } - imo->imo_num_memberships++; + + ip_mfilter_insert(&imo->imo_head, imf); imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = CARP_DFLTTL; imo->imo_multicast_loop = 0; @@ -1398,17 +1401,16 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) case AF_INET6: { struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f[2]; struct in6_addr in6; - struct in6_multi *in6m; - if (im6o->im6o_membership) + if (ip6_mfilter_first(&im6o->im6o_head)) return (0); - im6o->im6o_membership = (struct in6_multi **)malloc( - (sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP, - M_ZERO | M_WAITOK); - im6o->im6o_mfilters = NULL; - im6o->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; + im6f[0] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + im6f[1] = ip6_mfilter_alloc(M_WAITOK, 0, 0); + + ip6_mfilter_init(&im6o->im6o_head); im6o->im6o_multicast_hlim = CARP_DFLTTL; im6o->im6o_multicast_ifp = ifp; @@ -1417,17 +1419,15 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr16[0] = htons(0xff02); in6.s6_addr8[15] = 0x12; if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - free(im6o->im6o_membership, M_CARP); + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[0]->im6f_in6m, 0)) != 0) { + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[0] = in6m; - im6o->im6o_num_memberships++; /* Join solicited multicast address. */ bzero(&in6, sizeof(in6)); @@ -1436,20 +1436,21 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr32[2] = htonl(1); in6.s6_addr32[3] = 0; in6.s6_addr8[12] = 0xff; + if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m = NULL; - if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { - in6_leavegroup(im6o->im6o_membership[0], NULL); - free(im6o->im6o_membership, M_CARP); + + if ((error = in6_joingroup(ifp, &in6, NULL, &im6f[1]->im6f_in6m, 0)) != 0) { + in6_leavegroup(im6f[0]->im6f_in6m, NULL); + ip6_mfilter_free(im6f[0]); + ip6_mfilter_free(im6f[1]); break; } - in6m_acquire(in6m); - im6o->im6o_membership[1] = in6m; - im6o->im6o_num_memberships++; + ip6_mfilter_insert(&im6o->im6o_head, im6f[0]); + ip6_mfilter_insert(&im6o->im6o_head, im6f[1]); break; } #endif @@ -1464,35 +1465,38 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) static void carp_multicast_cleanup(struct carp_if *cif, sa_family_t sa) { - +#ifdef INET + struct ip_moptions *imo = &cif->cif_imo; + struct in_mfilter *imf; +#endif +#ifdef INET6 + struct ip6_moptions *im6o = &cif->cif_im6o; + struct in6_mfilter *im6f; +#endif sx_assert(&carp_sx, SA_XLOCKED); switch (sa) { #ifdef INET case AF_INET: - if (cif->cif_naddrs == 0) { - struct ip_moptions *imo = &cif->cif_imo; - - in_leavegroup(imo->imo_membership[0], NULL); - KASSERT(imo->imo_mfilters == NULL, - ("%s: imo_mfilters != NULL", __func__)); - free(imo->imo_membership, M_CARP); - imo->imo_membership = NULL; + if (cif->cif_naddrs != 0) + break; + while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { + ip_mfilter_remove(&imo->imo_head, imf); + in_leavegroup(imf->imf_inm, NULL); + ip_mfilter_free(imf); } break; #endif #ifdef INET6 case AF_INET6: - if (cif->cif_naddrs6 == 0) { - struct ip6_moptions *im6o = &cif->cif_im6o; - - in6_leavegroup(im6o->im6o_membership[0], NULL); - in6_leavegroup(im6o->im6o_membership[1], NULL); - KASSERT(im6o->im6o_mfilters == NULL, - ("%s: im6o_mfilters != NULL", __func__)); - free(im6o->im6o_membership, M_CARP); - im6o->im6o_membership = NULL; + if (cif->cif_naddrs6 != 0) + break; + + while ((im6f = ip6_mfilter_first(&im6o->im6o_head)) != NULL) { + ip6_mfilter_remove(&im6o->im6o_head, im6f); + in6_leavegroup(im6f->im6f_in6m, NULL); + ip6_mfilter_free(im6f); } break; #endif @@ -2178,21 +2182,6 @@ static struct protosw in6_carp_protosw = { }; #endif -#ifdef VIMAGE -#if defined(__i386__) -/* - * XXX This is a hack to work around an absolute relocation outside - * set_vnet by one (on the stop symbol) for carpstats. Add a dummy variable - * to the end of the file in the hope that the linker will just keep the - * order (as it seems to do at the moment). It is understood to be fragile. - * See PR 230857 for a longer discussion of the problem and the referenced - * review for possible alternate solutions. Each is a hack; we just need - * the least intrusive one for the next release. - */ -VNET_DEFINE(char, carp_zzz) = 0xde; -#endif -#endif - static void carp_mod_cleanup(void) { |