From owner-svn-src-all@FreeBSD.ORG Wed Aug 11 00:51:51 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 730F3106566B; Wed, 11 Aug 2010 00:51:51 +0000 (UTC) (envelope-from will@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 606E08FC17; Wed, 11 Aug 2010 00:51:51 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o7B0ppk0085010; Wed, 11 Aug 2010 00:51:51 GMT (envelope-from will@svn.freebsd.org) Received: (from will@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o7B0pp10084996; Wed, 11 Aug 2010 00:51:51 GMT (envelope-from will@svn.freebsd.org) Message-Id: <201008110051.o7B0pp10084996@svn.freebsd.org> From: Will Andrews Date: Wed, 11 Aug 2010 00:51:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r211157 - in head/sys: modules modules/if_carp net netinet netinet6 X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Aug 2010 00:51:51 -0000 Author: will Date: Wed Aug 11 00:51:50 2010 New Revision: 211157 URL: http://svn.freebsd.org/changeset/base/211157 Log: Allow carp(4) to be loaded as a kernel module. Follow precedent set by bridge(4), lagg(4) etc. and make use of function pointers and pf_proto_register() to hook carp into the network stack. Currently, because of the uncertainty about whether the unload path is free of race condition panics, unloads are disallowed by default. Compiling with CARPMOD_CAN_UNLOAD in CFLAGS removes this anti foot shooting measure. This commit requires IP6PROTOSPACER, introduced in r211115. Reviewed by: bz, simon Approved by: ken (mentor) MFC after: 2 weeks Added: head/sys/modules/if_carp/ head/sys/modules/if_carp/Makefile (contents, props changed) Modified: head/sys/modules/Makefile head/sys/net/if.c head/sys/net/if_bridge.c head/sys/net/if_ethersubr.c head/sys/netinet/if_ether.c head/sys/netinet/in.c head/sys/netinet/in_proto.c head/sys/netinet/ip_carp.c head/sys/netinet/ip_carp.h head/sys/netinet/ip_input.c head/sys/netinet6/in6_proto.c head/sys/netinet6/nd6_nbr.c Modified: head/sys/modules/Makefile ============================================================================== --- head/sys/modules/Makefile Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/modules/Makefile Wed Aug 11 00:51:50 2010 (r211157) @@ -112,6 +112,7 @@ SUBDIR= ${_3dfx} \ ${_ida} \ ${_ie} \ if_bridge \ + if_carp \ if_disc \ if_edsc \ if_ef \ Added: head/sys/modules/if_carp/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/modules/if_carp/Makefile Wed Aug 11 00:51:50 2010 (r211157) @@ -0,0 +1,21 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../netinet + +.include + +KMOD= if_carp +SRCS= ip_carp.c +SRCS+= opt_carp.h opt_bpf.h opt_inet.h opt_inet6.h vnode_if.h + +.if !defined(KERNBUILDDIR) +opt_inet.h: + @echo "#define INET 1" > ${.TARGET} + +.if ${MK_INET6_SUPPORT} != "no" +opt_inet6.h: + @echo "#define INET6 1" > ${.TARGET} +.endif +.endif + +.include Modified: head/sys/net/if.c ============================================================================== --- head/sys/net/if.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/net/if.c Wed Aug 11 00:51:50 2010 (r211157) @@ -33,7 +33,6 @@ #include "opt_compat.h" #include "opt_inet6.h" #include "opt_inet.h" -#include "opt_carp.h" #include "opt_ddb.h" #include @@ -89,11 +88,6 @@ #ifdef INET #include #endif -#if defined(INET) || defined(INET6) -#ifdef DEV_CARP -#include -#endif -#endif #include @@ -130,6 +124,7 @@ SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifn void (*bstp_linkstate_p)(struct ifnet *ifp, int state); void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); void (*lagg_linkstate_p)(struct ifnet *ifp, int state); +void (*carp_linkstate_p)(struct ifnet *ifp); struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; @@ -1813,12 +1808,8 @@ if_unroute(struct ifnet *ifp, int flag, pfctlinput(PRC_IFDOWN, ifa->ifa_addr); ifp->if_qflush(ifp); -#if defined(INET) || defined(INET6) -#ifdef DEV_CARP if (ifp->if_carp) - carp_carpdev_state(ifp->if_carp); -#endif -#endif + (*carp_linkstate_p)(ifp); rt_ifmsg(ifp); } @@ -1839,12 +1830,8 @@ if_route(struct ifnet *ifp, int flag, in TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFUP, ifa->ifa_addr); -#if defined(INET) || defined(INET6) -#ifdef DEV_CARP if (ifp->if_carp) - carp_carpdev_state(ifp->if_carp); -#endif -#endif + (*carp_linkstate_p)(ifp); rt_ifmsg(ifp); #ifdef INET6 in6_if_up(ifp); @@ -1887,12 +1874,8 @@ do_link_state_change(void *arg, int pend if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && IFP2AC(ifp)->ac_netgraph != NULL) (*ng_ether_link_state_p)(ifp, link_state); -#if defined(INET) || defined(INET6) -#ifdef DEV_CARP if (ifp->if_carp) - carp_carpdev_state(ifp->if_carp); -#endif -#endif + (*carp_linkstate_p)(ifp); if (ifp->if_bridge) { KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); (*bstp_linkstate_p)(ifp, link_state); Modified: head/sys/net/if_bridge.c ============================================================================== --- head/sys/net/if_bridge.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/net/if_bridge.c Wed Aug 11 00:51:50 2010 (r211157) @@ -79,7 +79,6 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" -#include "opt_carp.h" #include #include @@ -121,10 +120,8 @@ __FBSDID("$FreeBSD$"); #include #endif #if defined(INET) || defined(INET6) -#ifdef DEV_CARP #include #endif -#endif #include #include /* for struct arpcom */ #include @@ -2144,6 +2141,10 @@ drop: m_freem(m); } +#if defined(INET) || defined(INET6) +int (*carp_forus_p)(struct carp_if *, u_char *); +#endif + /* * bridge_input: * @@ -2252,13 +2253,13 @@ bridge_input(struct ifnet *ifp, struct m return (m); } -#if (defined(INET) || defined(INET6)) && defined(DEV_CARP) +#if (defined(INET) || defined(INET6)) # define OR_CARP_CHECK_WE_ARE_DST(iface) \ || ((iface)->if_carp \ - && carp_forus((iface)->if_carp, eh->ether_dhost)) + && (*carp_forus_p)((iface)->if_carp, eh->ether_dhost)) # define OR_CARP_CHECK_WE_ARE_SRC(iface) \ || ((iface)->if_carp \ - && carp_forus((iface)->if_carp, eh->ether_shost)) + && (*carp_forus_p)((iface)->if_carp, eh->ether_shost)) #else # define OR_CARP_CHECK_WE_ARE_DST(iface) # define OR_CARP_CHECK_WE_ARE_SRC(iface) Modified: head/sys/net/if_ethersubr.c ============================================================================== --- head/sys/net/if_ethersubr.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/net/if_ethersubr.c Wed Aug 11 00:51:50 2010 (r211157) @@ -35,7 +35,6 @@ #include "opt_inet6.h" #include "opt_ipx.h" #include "opt_netgraph.h" -#include "opt_carp.h" #include "opt_mbuf_profiling.h" #include @@ -70,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -78,12 +78,6 @@ #include #endif -#if defined(INET) || defined(INET6) -#ifdef DEV_CARP -#include -#endif -#endif - #ifdef IPX #include #include @@ -120,6 +114,11 @@ void (*ng_ether_attach_p)(struct ifnet * void (*ng_ether_detach_p)(struct ifnet *ifp); void (*vlan_input_p)(struct ifnet *, struct mbuf *); +#if defined(INET) || defined(INET6) +int (*carp_forus_p)(struct ifnet *, u_char *); +int (*carp_output_p)(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); +#endif /* if_bridge(4) support */ struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); @@ -399,12 +398,10 @@ ether_output(struct ifnet *ifp, struct m } #if defined(INET) || defined(INET6) -#ifdef DEV_CARP if (ifp->if_carp && - (error = carp_output(ifp, m, dst, NULL))) + (error = (*carp_output_p)(ifp, m, dst, NULL))) goto bad; #endif -#endif /* Handle ng_ether(4) processing, if any */ if (IFP2AC(ifp)->ac_netgraph != NULL) { @@ -724,7 +721,6 @@ ether_input(struct ifnet *ifp, struct mb } #if defined(INET) || defined(INET6) -#ifdef DEV_CARP /* * Clear M_PROMISC on frame so that carp(4) will see it when the * mbuf flows up to Layer 3. @@ -735,11 +731,10 @@ ether_input(struct ifnet *ifp, struct mb * TODO: Maintain a hash table of ethernet addresses other than * ether_dhost which may be active on this ifp. */ - if (ifp->if_carp && carp_forus(ifp->if_carp, eh->ether_dhost)) { + if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) { m->m_flags &= ~M_PROMISC; } else #endif -#endif { /* * If the frame received was not for our MAC address, set the Modified: head/sys/netinet/if_ether.c ============================================================================== --- head/sys/netinet/if_ether.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet/if_ether.c Wed Aug 11 00:51:50 2010 (r211157) @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" -#include "opt_carp.h" #include #include @@ -69,10 +68,6 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_CARP -#include -#endif - #include #define SIN(s) ((struct sockaddr_in *)s) @@ -123,6 +118,10 @@ static void arptimer(void *); #ifdef INET static void in_arpinput(struct mbuf *); #endif +#if defined(INET) || defined(INET6) +int (*carp_iamatch_p)(struct ifnet *, struct in_ifaddr *, struct in_addr *, + u_int8_t **); +#endif static const struct netisr_handler arp_nh = { .nh_name = "arp", @@ -494,9 +493,7 @@ in_arpinput(struct mbuf *m) int op, flags; int req_len; int bridged = 0, is_bridge = 0; -#ifdef DEV_CARP int carp_match = 0; -#endif struct sockaddr_in sin; sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; @@ -539,16 +536,14 @@ in_arpinput(struct mbuf *m) IN_IFADDR_RUNLOCK(); goto match; } -#ifdef DEV_CARP if (ifp->if_carp != NULL && - carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && + (*carp_iamatch_p)(ifp, ia, &isaddr, &enaddr) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { carp_match = 1; ifa_ref(&ia->ia_ifa); IN_IFADDR_RUNLOCK(); goto match; } -#endif } LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) if (((bridged && ia->ia_ifp->if_bridge != NULL) || @@ -648,11 +643,7 @@ match: IF_AFDATA_UNLOCK(ifp); if (la != NULL) { /* the following is not an error when doing bridging */ - if (!bridged && la->lle_tbl->llt_ifp != ifp -#ifdef DEV_CARP - && (ifp->if_type != IFT_CARP || !carp_match) -#endif - ) { + if (!bridged && la->lle_tbl->llt_ifp != ifp && !carp_match) { if (log_arp_wrong_iface) log(LOG_ERR, "arp: %s is on %s " "but got reply from %*D on %s\n", Modified: head/sys/netinet/in.c ============================================================================== --- head/sys/netinet/in.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet/in.c Wed Aug 11 00:51:50 2010 (r211157) @@ -33,7 +33,6 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_carp.h" #include "opt_mpath.h" #include @@ -891,13 +890,11 @@ in_ifinit(struct ifnet *ifp, struct in_i ia->ia_net = i & ia->ia_netmask; ia->ia_subnet = i & ia->ia_subnetmask; in_socktrim(&ia->ia_sockmask); -#ifdef DEV_CARP /* * XXX: carp(4) does not have interface route */ if (ifp->if_type == IFT_CARP) return (0); -#endif /* * Add route for the network. */ @@ -1152,12 +1149,12 @@ in_scrubprefix(struct in_ifaddr *target) * the route itself to it. Make sure that routing daemons * get a heads-up. * - * XXX: a special case for carp(4) interface + * XXX: a special case for carp(4) interface - this should + * be more generally specified as an interface that + * doesn't support such action. */ if ((ia->ia_flags & IFA_ROUTE) == 0 -#ifdef DEV_CARP && (ia->ia_ifp->if_type != IFT_CARP) -#endif ) { IN_IFADDR_RUNLOCK(); rtinit(&(target->ia_ifa), (int)RTM_DELETE, Modified: head/sys/netinet/in_proto.c ============================================================================== --- head/sys/netinet/in_proto.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet/in_proto.c Wed Aug 11 00:51:50 2010 (r211157) @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include "opt_ipsec.h" #include "opt_inet6.h" #include "opt_pf.h" -#include "opt_carp.h" #include "opt_sctp.h" #include "opt_mpath.h" @@ -94,10 +93,6 @@ static struct pr_usrreqs nousrreqs; #include #endif -#ifdef DEV_CARP -#include -#endif - extern struct domain inetdomain; /* Spacer for loadable protocols. */ @@ -330,18 +325,6 @@ struct protosw inetsw[] = { .pr_usrreqs = &rip_usrreqs }, #endif /* DEV_PFSYNC */ -#ifdef DEV_CARP -{ - .pr_type = SOCK_RAW, - .pr_domain = &inetdomain, - .pr_protocol = IPPROTO_CARP, - .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = carp_input, - .pr_output = (pr_output_t*)rip_output, - .pr_ctloutput = rip_ctloutput, - .pr_usrreqs = &rip_usrreqs -}, -#endif /* DEV_CARP */ /* Spacer n-times for loadable protocols. */ IPPROTOSPACER, IPPROTOSPACER, @@ -413,6 +396,3 @@ SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, #ifdef DEV_PFSYNC SYSCTL_NODE(_net_inet, IPPROTO_PFSYNC, pfsync, CTLFLAG_RW, 0, "PFSYNC"); #endif -#ifdef DEV_CARP -SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); -#endif Modified: head/sys/netinet/ip_carp.c ============================================================================== --- head/sys/netinet/ip_carp.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet/ip_carp.c Wed Aug 11 00:51:50 2010 (r211157) @@ -27,7 +27,6 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_carp.h" #include "opt_bpf.h" #include "opt_inet.h" #include "opt_inet6.h" @@ -44,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -79,6 +79,7 @@ __FBSDID("$FreeBSD$"); #ifdef INET6 #include #include +#include #include #include #include @@ -134,8 +135,29 @@ struct carp_softc { }; #define SC2IFP(sc) ((sc)->sc_ifp) +/* These are external networking stack hooks for CARP */ +/* net/if.c */ +extern void (*carp_linkstate_p)(struct ifnet *); +/* net/if_bridge.c net/if_ethersubr.c */ +extern struct ifnet *(*carp_forus_p)(struct ifnet *, u_char *); +/* net/if_ethersubr.c */ +extern int (*carp_output_p)(struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *); +#ifdef INET +/* netinet/if_ether.c */ +extern int (*carp_iamatch_p)(struct ifnet *, struct in_ifaddr *, + struct in_addr *, u_int8_t **); +#endif +#ifdef INET6 +/* netinet6/nd6_nbr.c */ +extern struct ifaddr *(*carp_iamatch6_p)(struct ifnet *, struct in6_addr *); +extern caddr_t (*carp_macmatch6_p)(struct ifnet *, struct mbuf *, + const struct in6_addr *); +#endif + int carp_suppress_preempt = 0; int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 1, 0, 0 }; /* XXX for now */ +SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); SYSCTL_INT(_net_inet_carp, CARPCTL_ALLOW, allow, CTLFLAG_RW, &carp_opts[CARPCTL_ALLOW], 0, "Accept incoming CARP packets"); SYSCTL_INT(_net_inet_carp, CARPCTL_PREEMPT, preempt, CTLFLAG_RW, @@ -160,6 +182,10 @@ struct carp_if { struct mtx vhif_mtx; }; +#define CARP_INET 0 +#define CARP_INET6 1 +static int proto_reg[] = {-1, -1}; + /* Get carp_if from softc. Valid after carp_set_addr{,6}. */ #define SC2CIF(sc) ((struct carp_if *)(sc)->sc_carpdev->if_carp) @@ -1146,14 +1172,15 @@ carp_addrcount(struct carp_if *cif, stru } int -carp_iamatch(void *v, struct in_ifaddr *ia, +carp_iamatch(struct ifnet *ifp, struct in_ifaddr *ia, struct in_addr *isaddr, u_int8_t **enaddr) { - struct carp_if *cif = v; + struct carp_if *cif; struct carp_softc *vh; int index, count = 0; struct ifaddr *ifa; + cif = ifp->if_carp; CARP_LOCK(cif); if (carp_opts[CARPCTL_ARPBALANCE]) { @@ -1222,12 +1249,13 @@ carp_iamatch(void *v, struct in_ifaddr * #ifdef INET6 struct ifaddr * -carp_iamatch6(void *v, struct in6_addr *taddr) +carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) { - struct carp_if *cif = v; + struct carp_if *cif; struct carp_softc *vh; struct ifaddr *ifa; + cif = ifp->if_carp; CARP_LOCK(cif); TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { IF_ADDR_LOCK(SC2IFP(vh)); @@ -1250,14 +1278,15 @@ carp_iamatch6(void *v, struct in6_addr * return (NULL); } -void * -carp_macmatch6(void *v, struct mbuf *m, const struct in6_addr *taddr) +caddr_t +carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) { struct m_tag *mtag; - struct carp_if *cif = v; + struct carp_if *cif; struct carp_softc *sc; struct ifaddr *ifa; + cif = ifp->if_carp; CARP_LOCK(cif); TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) { IF_ADDR_LOCK(SC2IFP(sc)); @@ -1293,15 +1322,16 @@ carp_macmatch6(void *v, struct mbuf *m, #endif struct ifnet * -carp_forus(void *v, void *dhost) +carp_forus(struct ifnet *ifp, u_char *dhost) { - struct carp_if *cif = v; + struct carp_if *cif; struct carp_softc *vh; u_int8_t *ena = dhost; if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1) return (NULL); + cif = ifp->if_carp; CARP_LOCK(cif); TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) if ((SC2IFP(vh)->if_flags & IFF_UP) && @@ -2210,10 +2240,11 @@ carp_set_state(struct carp_softc *sc, in } void -carp_carpdev_state(void *v) +carp_carpdev_state(struct ifnet *ifp) { - struct carp_if *cif = v; + struct carp_if *cif; + cif = ifp->if_carp; CARP_LOCK(cif); carp_carpdev_state_locked(cif); CARP_UNLOCK(cif); @@ -2264,24 +2295,121 @@ carp_sc_state_locked(struct carp_softc * return; } +#ifdef INET +extern struct domain inetdomain; +static struct protosw in_carp_protosw = { + .pr_type = SOCK_RAW, + .pr_domain = &inetdomain, + .pr_protocol = IPPROTO_CARP, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_input = carp_input, + .pr_output = (pr_output_t *)rip_output, + .pr_ctloutput = rip_ctloutput, + .pr_usrreqs = &rip_usrreqs +}; +#endif + +#ifdef INET6 +extern struct domain inet6domain; +static struct ip6protosw in6_carp_protosw = { + .pr_type = SOCK_RAW, + .pr_domain = &inet6domain, + .pr_protocol = IPPROTO_CARP, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_input = carp6_input, + .pr_output = rip6_output, + .pr_ctloutput = rip6_ctloutput, + .pr_usrreqs = &rip6_usrreqs +}; +#endif + +static void +carp_mod_cleanup(void) +{ + + if (if_detach_event_tag == NULL) + return; + EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag); + if_clone_detach(&carp_cloner); +#ifdef INET + if (proto_reg[CARP_INET] == 0) { + pf_proto_unregister(PF_INET, IPPROTO_CARP, SOCK_RAW); + proto_reg[CARP_INET] = -1; + } + carp_iamatch_p = NULL; +#endif +#ifdef INET6 + if (proto_reg[CARP_INET6] == 0) { + pf_proto_unregister(PF_INET6, IPPROTO_CARP, SOCK_RAW); + proto_reg[CARP_INET6] = -1; + } + carp_iamatch6_p = NULL; + carp_macmatch6_p = NULL; +#endif + carp_linkstate_p = NULL; + carp_forus_p = NULL; + carp_output_p = NULL; + mtx_destroy(&carp_mtx); +} + +static int +carp_mod_load(void) +{ + + 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); + carp_linkstate_p = carp_carpdev_state; + carp_forus_p = carp_forus; + carp_output_p = carp_output; +#ifdef INET6 + carp_iamatch6_p = carp_iamatch6; + carp_macmatch6_p = carp_macmatch6; + proto_reg[CARP_INET6] = pf_proto_register(PF_INET6, + (struct protosw *)&in6_carp_protosw); + if (proto_reg[CARP_INET6] != 0) { + printf("carp: error %d attaching to PF_INET6\n", + proto_reg[CARP_INET6]); + carp_mod_cleanup(); + return (EINVAL); + } +#endif +#ifdef INET + carp_iamatch_p = carp_iamatch; + proto_reg[CARP_INET] = pf_proto_register(PF_INET, &in_carp_protosw); + if (proto_reg[CARP_INET] != 0) { + printf("carp: error %d attaching to PF_INET\n", + proto_reg[CARP_INET]); + carp_mod_cleanup(); + return (EINVAL); + } +#endif + return 0; +} + static int carp_modevent(module_t mod, int type, void *data) { 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; - + return carp_mod_load(); + /* NOTREACHED */ case MOD_UNLOAD: - EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag); - if_clone_detach(&carp_cloner); - mtx_destroy(&carp_mtx); + /* + * XXX: For now, disallow module unloading by default due to + * a race condition where a thread may dereference one of the + * function pointer hooks after the module has been + * unloaded, during processing of a packet, causing a panic. + */ +#ifdef CARPMOD_CAN_UNLOAD + carp_mod_cleanup(); +#else + return (EBUSY); +#endif break; default: Modified: head/sys/netinet/ip_carp.h ============================================================================== --- head/sys/netinet/ip_carp.h Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet/ip_carp.h Wed Aug 11 00:51:50 2010 (r211157) @@ -157,15 +157,15 @@ struct carpreq { } #ifdef _KERNEL -void carp_carpdev_state(void *); +void carp_carpdev_state(struct ifnet *); void carp_input (struct mbuf *, int); int carp6_input (struct mbuf **, int *, int); int carp_output (struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); -int carp_iamatch (void *, struct in_ifaddr *, struct in_addr *, +int carp_iamatch (struct ifnet *, struct in_ifaddr *, struct in_addr *, u_int8_t **); -struct ifaddr *carp_iamatch6(void *, struct in6_addr *); -void *carp_macmatch6(void *, struct mbuf *, const struct in6_addr *); -struct ifnet *carp_forus (void *, void *); +struct ifaddr *carp_iamatch6(struct ifnet *, struct in6_addr *); +caddr_t carp_macmatch6(struct ifnet *, struct mbuf *, const struct in6_addr *); +struct ifnet *carp_forus (struct ifnet *, u_char *); #endif #endif /* _IP_CARP_H */ Modified: head/sys/netinet/ip_input.c ============================================================================== --- head/sys/netinet/ip_input.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet/ip_input.c Wed Aug 11 00:51:50 2010 (r211157) @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include "opt_ipstealth.h" #include "opt_ipsec.h" #include "opt_route.h" -#include "opt_carp.h" #include #include @@ -74,9 +73,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef DEV_CARP #include -#endif #ifdef IPSEC #include #endif /* IPSEC */ @@ -606,10 +603,7 @@ passin: */ checkif = V_ip_checkinterface && (V_ipforwarding == 0) && ifp != NULL && ((ifp->if_flags & IFF_LOOPBACK) == 0) && -#ifdef DEV_CARP - !ifp->if_carp && -#endif - (dchg == 0); + ifp->if_carp == NULL && (dchg == 0); /* * Check for exact addresses in the hash bucket. Modified: head/sys/netinet6/in6_proto.c ============================================================================== --- head/sys/netinet6/in6_proto.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet6/in6_proto.c Wed Aug 11 00:51:50 2010 (r211157) @@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$"); #include "opt_inet6.h" #include "opt_ipsec.h" #include "opt_ipstealth.h" -#include "opt_carp.h" #include "opt_sctp.h" #include "opt_mpath.h" #include "opt_route.h" @@ -112,10 +111,6 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_CARP -#include -#endif - #ifdef SCTP #include #include @@ -336,18 +331,6 @@ struct ip6protosw inet6sw[] = { .pr_ctloutput = rip6_ctloutput, .pr_usrreqs = &rip6_usrreqs }, -#ifdef DEV_CARP -{ - .pr_type = SOCK_RAW, - .pr_domain = &inet6domain, - .pr_protocol = IPPROTO_CARP, - .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = carp6_input, - .pr_output = rip6_output, - .pr_ctloutput = rip6_ctloutput, - .pr_usrreqs = &rip6_usrreqs -}, -#endif /* DEV_CARP */ /* Spacer n-times for loadable protocols. */ IP6PROTOSPACER, IP6PROTOSPACER, Modified: head/sys/netinet6/nd6_nbr.c ============================================================================== --- head/sys/netinet6/nd6_nbr.c Tue Aug 10 22:57:43 2010 (r211156) +++ head/sys/netinet6/nd6_nbr.c Wed Aug 11 00:51:50 2010 (r211157) @@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" -#include "opt_carp.h" #include "opt_mpath.h" #include @@ -74,10 +73,6 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_CARP -#include -#endif - #define SDL(s) ((struct sockaddr_dl *)s) struct dadq; @@ -89,6 +84,10 @@ static void nd6_dad_ns_output(struct dad static void nd6_dad_ns_input(struct ifaddr *); static void nd6_dad_na_input(struct ifaddr *); +struct ifaddr *(*carp_iamatch6_p)(struct ifnet *, struct in6_addr *); +caddr_t (*carp_macmatch6_p)(struct ifnet *, struct mbuf *, + const struct in6_addr *); + VNET_DEFINE(int, dad_ignore_ns) = 0; /* ignore NS in DAD - specwise incorrect*/ VNET_DEFINE(int, dad_maxtry) = 15; /* max # of *tries* to transmit DAD packet */ #define V_dad_ignore_ns VNET(dad_ignore_ns) @@ -222,14 +221,10 @@ nd6_ns_input(struct mbuf *m, int off, in * (3) "tentative" address on which DAD is being performed. */ /* (1) and (3) check. */ -#ifdef DEV_CARP if (ifp->if_carp) - ifa = carp_iamatch6(ifp->if_carp, &taddr6); + ifa = (*carp_iamatch6_p)(ifp, &taddr6); if (ifa == NULL) ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); -#else - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); -#endif /* (2) check. */ if (ifa == NULL) { @@ -1029,14 +1024,10 @@ nd6_na_output(struct ifnet *ifp, const s * my address) use lladdr configured for the interface. */ if (sdl0 == NULL) { -#ifdef DEV_CARP if (ifp->if_carp) - mac = carp_macmatch6(ifp->if_carp, m, taddr6); + mac = (*carp_macmatch6_p)(ifp, m, taddr6); if (mac == NULL) mac = nd6_ifptomac(ifp); -#else - mac = nd6_ifptomac(ifp); -#endif } else if (sdl0->sa_family == AF_LINK) { struct sockaddr_dl *sdl; sdl = (struct sockaddr_dl *)sdl0;