svn commit: r211157 - in head/sys: modules modules/if_carp net netinet netinet6

Will Andrews will at FreeBSD.org
Wed Aug 11 00:51:51 UTC 2010


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 <bsd.own.mk>
+
+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 <bsd.kmod.mk>

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 <sys/param.h>
@@ -89,11 +88,6 @@
 #ifdef INET
 #include <netinet/if_ether.h>
 #endif
-#if defined(INET) || defined(INET6)
-#ifdef DEV_CARP
-#include <netinet/ip_carp.h>
-#endif
-#endif
 
 #include <security/mac/mac_framework.h>
 
@@ -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 <sys/param.h>
 #include <sys/mbuf.h>
@@ -121,10 +120,8 @@ __FBSDID("$FreeBSD$");
 #include <netinet6/ip6_var.h>
 #endif
 #if defined(INET) || defined(INET6)
-#ifdef DEV_CARP
 #include <netinet/ip_carp.h>
 #endif
-#endif
 #include <machine/in_cksum.h>
 #include <netinet/if_ether.h> /* for struct arpcom */
 #include <net/bridgestp.h>
@@ -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 <sys/param.h>
@@ -70,6 +69,7 @@
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/if_ether.h>
+#include <netinet/ip_carp.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip_fw.h>
 #include <netinet/ipfw/ip_fw_private.h>
@@ -78,12 +78,6 @@
 #include <netinet6/nd6.h>
 #endif
 
-#if defined(INET) || defined(INET6)
-#ifdef DEV_CARP
-#include <netinet/ip_carp.h>
-#endif
-#endif
-
 #ifdef IPX
 #include <netipx/ipx.h>
 #include <netipx/ipx_if.h>
@@ -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 <sys/param.h>
 #include <sys/kernel.h>
@@ -69,10 +68,6 @@ __FBSDID("$FreeBSD$");
 #include <net/if_arc.h>
 #include <net/iso88025.h>
 
-#ifdef DEV_CARP
-#include <netinet/ip_carp.h>
-#endif
-
 #include <security/mac/mac_framework.h>
 
 #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 <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include "opt_carp.h"
 #include "opt_mpath.h"
 
 #include <sys/param.h>
@@ -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 <net/if_pfsync.h>
 #endif
 
-#ifdef DEV_CARP
-#include <netinet/ip_carp.h>
-#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 <sys/cdefs.h>
 __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 <sys/time.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/protosw.h>
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/signalvar.h>
@@ -79,6 +79,7 @@ __FBSDID("$FreeBSD$");
 #ifdef INET6
 #include <netinet/icmp6.h>
 #include <netinet/ip6.h>
+#include <netinet6/ip6protosw.h>
 #include <netinet6/ip6_var.h>
 #include <netinet6/scope6_var.h>
 #include <netinet6/nd6.h>
@@ -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 <sys/param.h>
 #include <sys/systm.h>
@@ -74,9 +73,7 @@ __FBSDID("$FreeBSD$");
 #include <netinet/ip_icmp.h>
 #include <netinet/ip_options.h>
 #include <machine/in_cksum.h>
-#ifdef DEV_CARP
 #include <netinet/ip_carp.h>
-#endif
 #ifdef IPSEC
 #include <netinet/ip_ipsec.h>
 #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 <netinet6/pim6_var.h>
 #include <netinet6/nd6.h>
 
-#ifdef DEV_CARP
-#include <netinet/ip_carp.h>
-#endif
-
 #ifdef SCTP
 #include <netinet/in_pcb.h>
 #include <netinet/sctp_pcb.h>
@@ -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 <sys/param.h>
@@ -74,10 +73,6 @@ __FBSDID("$FreeBSD$");
 #include <netinet6/nd6.h>
 #include <netinet/icmp6.h>
 
-#ifdef DEV_CARP
-#include <netinet/ip_carp.h>
-#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;


More information about the svn-src-all mailing list