--- /router/usr/src/sbin/ifconfig/ifcarp.c	Tue Feb 22 15:07:47 2005
+++ /usr/src/sbin/ifconfig/ifcarp.c	Sat Sep 15 02:53:47 2007
@@ -57,12 +57,14 @@
 void setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
 void setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
 void setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
+void setcarp_carpdev(const char *, int, int, const struct afswtch *rafp);
 
 void
 carp_status(int s)
 {
 	const char *state;
 	struct carpreq carpr;
+	char carpdev[IFNAMSIZ];
 
 	memset((char *)&carpr, 0, sizeof(struct carpreq));
 	ifr.ifr_data = (caddr_t)&carpr;
@@ -76,9 +78,17 @@
 		else
 			state = carp_states[carpr.carpr_state];
 
-		printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
-		    state, carpr.carpr_vhid, carpr.carpr_advbase,
-		    carpr.carpr_advskew);
+		if (carpr.carpr_carpdev > 0) {
+			if (if_indextoname(carpr.carpr_carpdev, carpdev) != NULL) {
+				printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n",
+				    state, carpdev, carpr.carpr_vhid, 
+				    carpr.carpr_advbase, carpr.carpr_advskew);
+			}
+		} else {
+			printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
+				state, carpr.carpr_vhid, carpr.carpr_advbase,
+				carpr.carpr_advskew);
+		}
 	}
 
 	return;
@@ -130,6 +140,31 @@
 	return;
 }
 
+void 
+setcarp_carpdev(const char *val, int d, int s, const struct afswtch *afp)
+{
+	int carpdev;
+	struct carpreq carpr;
+	
+	carpdev = if_nametoindex(val);
+	if (carpdev == 0)
+		errx(1, "interface %s does not exist",val);
+	
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data = (caddr_t)&carpr;
+	
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCGVH");
+	
+	carpr.carpr_carpdev = carpdev;
+	
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+		err(1, "SIOCSVH");
+		
+	return;
+}	
+	
+
 void
 setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
 {
@@ -179,6 +214,7 @@
 	DEF_CMD_ARG("advskew",	setcarp_advskew),
 	DEF_CMD_ARG("pass",	setcarp_passwd),
 	DEF_CMD_ARG("vhid",	setcarp_vhid),
+	DEF_CMD_ARG("carpdev",  setcarp_carpdev),
 };
 static struct afswtch af_carp = {
 	.af_name	= "af_carp",
--- /router/usr/src/sys/netinet/ip_carp.h	Thu Aug 10 12:10:12 2006
+++ /usr/src/sys/netinet/ip_carp.h	Sat Sep 15 01:42:12 2007
@@ -121,6 +121,7 @@
 #define	CARP_STATES	"INIT", "BACKUP", "MASTER"
 #define	CARP_MAXSTATE	2
 	int		carpr_vhid;
+	int		carpr_carpdev;
 	int		carpr_advskew;
 	int		carpr_advbase;
 	unsigned char	carpr_key[CARP_KEY_LEN];
--- /router/usr/src/sys/netinet/ip_carp.c	Sat Jan 20 00:01:33 2007
+++ /usr/src/sys/netinet/ip_carp.c	Sat Sep 15 02:58:59 2007
@@ -110,6 +110,7 @@
 #define	CARP_SENDAD_MIN_SUCCESS 3
 
 	int			 sc_vhid;
+	int			 sc_carpdevindex; /* optional carp parent interface index */
 	int			 sc_advskew;
 	int			 sc_naddrs;
 	int			 sc_naddrs6;
@@ -369,6 +370,7 @@
 	sc->sc_suppress = 0;
 	sc->sc_advbase = CARP_DFLTINTV;
 	sc->sc_vhid = -1;	/* required setting */
+	sc->sc_carpdevindex = 0; /* required setting */
 	sc->sc_advskew = 0;
 	sc->sc_init_counter = 1;
 	sc->sc_naddrs = sc->sc_naddrs6 = 0; /* M_ZERO? */
@@ -1415,18 +1417,35 @@
 		return (0);
 	}
 
-	/* we have to do it by hands to check we won't match on us */
-	ia_if = NULL; own = 0;
-	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
-		/* and, yeah, we need a multicast-capable iface too */
-		if (ia->ia_ifp != SC2IFP(sc) &&
-		    (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
-		    (iaddr & ia->ia_subnetmask) == ia->ia_subnet) {
-			if (!ia_if)
-				ia_if = ia;
-			if (sin->sin_addr.s_addr ==
-			    ia->ia_addr.sin_addr.s_addr)
-				own++;
+	/* carpdev way */
+	if (sc->sc_carpdevindex > 0) {
+		ia_if = NULL; own = 0;
+		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+			/* and, yeah, we need a multicast-capable iface too */
+			if (ia->ia_ifp->if_flags & IFF_MULTICAST) {
+				if (ia->ia_ifp->if_index == sc->sc_carpdevindex) { /* found */
+					if (!ia_if)
+						ia_if = ia;
+					if (sin->sin_addr.s_addr ==
+					    ia->ia_addr.sin_addr.s_addr)
+						own++;
+				}
+			}
+		}
+	} else { /* traditional way */
+		/* we have to do it by hands to check we won't match on us */
+		ia_if = NULL; own = 0;
+		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+			/* and, yeah, we need a multicast-capable iface too */
+			if (ia->ia_ifp != SC2IFP(sc) &&
+			    (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
+			    (iaddr & ia->ia_subnetmask) == ia->ia_subnet) {
+				if (!ia_if)
+				   	ia_if = ia;
+				if (sin->sin_addr.s_addr ==
+			    	   ia->ia_addr.sin_addr.s_addr)
+				   	own++;
+			}
 		}
 	}
 
@@ -1576,27 +1595,44 @@
 		return (0);
 	}
 
-	/* we have to do it by hands to check we won't match on us */
-	ia_if = NULL; own = 0;
-	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
-		int i;
-
-		for (i = 0; i < 4; i++) {
-			if ((sin6->sin6_addr.s6_addr32[i] &
-			    ia->ia_prefixmask.sin6_addr.s6_addr32[i]) !=
-			    (ia->ia_addr.sin6_addr.s6_addr32[i] &
-			    ia->ia_prefixmask.sin6_addr.s6_addr32[i]))
-				break;
+	/* carpdev way */
+	if (sc->sc_carpdevindex > 0) {
+		ia_if = NULL; own = 0;
+		for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
+			if (ia->ia_ifp->if_index == sc->sc_carpdevindex) { /* found */
+				/* and, yeah, we need a multicast-capable iface too */
+				if (ia->ia_ifp->if_flags & IFF_MULTICAST) {
+					if (!ia_if)
+						ia_if = ia;
+					if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+					    &ia->ia_addr.sin6_addr))
+						own++;
+				}
+			}
 		}
-		/* and, yeah, we need a multicast-capable iface too */
-		if (ia->ia_ifp != SC2IFP(sc) &&
-		    (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
-		    (i == 4)) {
-			if (!ia_if)
-				ia_if = ia;
-			if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
-			    &ia->ia_addr.sin6_addr))
-				own++;
+	} else { /* traditional way */
+		/* we have to do it by hands to check we won't match on us */
+		ia_if = NULL; own = 0;
+		for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
+			int i;
+
+			for (i = 0; i < 4; i++) {
+				if ((sin6->sin6_addr.s6_addr32[i] &
+				    ia->ia_prefixmask.sin6_addr.s6_addr32[i]) !=
+				    (ia->ia_addr.sin6_addr.s6_addr32[i] &
+				    ia->ia_prefixmask.sin6_addr.s6_addr32[i]))
+					break;
+			}
+			/* and, yeah, we need a multicast-capable iface too */
+			if (ia->ia_ifp != SC2IFP(sc) &&
+			    (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
+			    (i == 4)) { /* <- who build this bad hack?? */
+				if (!ia_if)
+					ia_if = ia;
+				if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+				    &ia->ia_addr.sin6_addr))
+					own++;
+			}
 		}
 	}
 
@@ -1894,6 +1930,10 @@
 			IFP2ENADDR(sc->sc_ifp)[5] = sc->sc_vhid;
 			error--;
 		}
+		if (carpr.carpr_carpdev > 0) {
+			sc->sc_carpdevindex = carpr.carpr_carpdev;
+			/* fixme - update interface */
+		}
 		if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) {
 			if (carpr.carpr_advskew >= 255) {
 				error = EINVAL;
@@ -1921,6 +1961,7 @@
 		bzero(&carpr, sizeof(carpr));
 		carpr.carpr_state = sc->sc_state;
 		carpr.carpr_vhid = sc->sc_vhid;
+		carpr.carpr_carpdev = sc->sc_carpdevindex;
 		carpr.carpr_advbase = sc->sc_advbase;
 		carpr.carpr_advskew = sc->sc_advskew;
 		if (suser(curthread) == 0)
--- /router/usr/src/sbin/ifconfig/ifconfig.8	Mon Feb  5 13:39:53 2007
+++ /usr/src/sbin/ifconfig/ifconfig.8	Sat Sep 15 03:23:32 2007
@@ -1435,6 +1435,9 @@
 Set the virtual host ID.
 This is a required setting.
 Acceptable values are 1 to 255.
+.It Cm carpdev Ar interface
+Set the parent interface of carp device.
+This is a optional setting.
 .El
 .Pp
 The
