From owner-freebsd-pf@FreeBSD.ORG Sat Oct 27 21:10:50 2007 Return-Path: Delivered-To: freebsd-pf@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2ADE316A419 for ; Sat, 27 Oct 2007 21:10:50 +0000 (UTC) (envelope-from max@love2party.net) Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.126.187]) by mx1.freebsd.org (Postfix) with ESMTP id 3AA8613C4B8 for ; Sat, 27 Oct 2007 21:10:48 +0000 (UTC) (envelope-from max@love2party.net) Received: from [192.168.4.160] (dslb-088-066-000-061.pools.arcor-ip.net [88.66.0.61]) by mrelayeu.kundenserver.de (node=mrelayeu7) with ESMTP (Nemesis) id 0ML2xA-1Ilsvc13rf-0004vV; Sat, 27 Oct 2007 23:10:46 +0200 From: Max Laier Organization: FreeBSD To: freebsd-pf@freebsd.org Date: Sat, 27 Oct 2007 23:11:00 +0200 User-Agent: KMail/1.9.7 X-Face: ,,8R(x[kmU]tKN@>gtH1yQE4aslGdu+2]; R]*pL,U>^H?)gW@49@wdJ`H<%}*_BD U_or=\mOZf764&nYj=JYbR1PW0ud>|!~, , CPC.1-D$FG@0h3#'5"k{V]a~. X-Provags-ID: V01U2FsdGVkX18MFuEkShtbfn9dI89ckrePGLqOq5ffXW2puv9 TnKqeLR2LCDcd/M25axN8W7YU055eGn6evuO8jEzxgmTWOGHt1 fShO55MXCJFSPldeIg/hqICQjdWGnPQbwM/egW5CmQ= Subject: carpdev ... X-BeenThere: freebsd-pf@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Technical discussion and general questions about packet filter \(pf\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 27 Oct 2007 21:10:50 -0000 --nextPart3069786.LU2bnx6mTt Content-Type: multipart/mixed; boundary="Boundary-01=_nl6IH3bgJTGz2kl" Content-Transfer-Encoding: 7bit Content-Disposition: inline --Boundary-01=_nl6IH3bgJTGz2kl Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline =2E.. the neverending story continues :-\ I am making progress ... really, really slowly as I'm not at the top of my= =20 health (inflammation in my front teeth) and 7.0 got in the way, too. Anyways, here is something for *BETA* testing. Nobody put this in=20 production (or you deserve whatever goes wrong). But if you have spare=20 time and lab machines, please test and report back! Details welcome ;) IPv6 is still TBD. =2D-=20 /"\ Best regards, | mlaier@freebsd.org \ / Max Laier | ICQ #67774661 X http://pf4freebsd.love2party.net/ | mlaier@EFnet / \ ASCII Ribbon Campaign | Against HTML Mail and News --Boundary-01=_nl6IH3bgJTGz2kl Content-Type: text/x-diff; charset="us-ascii"; name="carpdev.BETA.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="carpdev.BETA.diff" =2D-- //depot/vendor/freebsd/src/contrib/pf/pflogd/pidfile.c 2007/07/03 14:= 46:49 +++ //depot/user/mlaier/carp2/contrib/pf/pflogd/pidfile.c 2007/09/12 12:13:= 13 @@ -1,4 +1,4 @@ =2D/* $FreeBSD: src/contrib/pf/pflogd/pidfile.c,v 1.6 2007/07/03 14:08:49 m= laier Exp $ */ +/* $FreeBSD: src/contrib/pf/pflogd/pidfile.c,v 1.4 2005/05/03 16:55:20 mla= ier Exp $ */ /* $OpenBSD: pidfile.c,v 1.5 2002/05/26 09:29:02 deraadt Exp $ */ /* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */ =20 =2D-- //depot/vendor/freebsd/src/contrib/pf/pflogd/pidfile.h 2007/07/03 14:= 46:49 +++ //depot/user/mlaier/carp2/contrib/pf/pflogd/pidfile.h 2007/09/12 12:13:= 13 @@ -1,3 +1,1 @@ =2D/* $FreeBSD: src/contrib/pf/pflogd/pidfile.h,v 1.3 2007/07/03 14:08:49 m= laier Exp $ */ =2D int pidfile(const char *); =2D-- //depot/vendor/freebsd/src/sbin/ifconfig/ifcarp.c 2005/02/22 14:37:13 +++ //depot/user/mlaier/carp2/sbin/ifconfig/ifcarp.c 2007/09/12 16:12:46 @@ -52,13 +52,7 @@ =20 static const char *carp_states[] =3D { CARP_STATES }; =20 =2Dvoid carp_status(int s); =2Dvoid setcarp_advbase(const char *,int, int, const struct afswtch *rafp); =2Dvoid setcarp_advskew(const char *, int, int, const struct afswtch *rafp); =2Dvoid setcarp_passwd(const char *, int, int, const struct afswtch *rafp); =2Dvoid setcarp_vhid(const char *, int, int, const struct afswtch *rafp); =2D =2Dvoid +static void carp_status(int s) { const char *state; @@ -76,17 +70,17 @@ else state =3D carp_states[carpr.carpr_state]; =20 =2D printf("\tcarp: %s vhid %d advbase %d advskew %d\n", =2D state, carpr.carpr_vhid, carpr.carpr_advbase, =2D carpr.carpr_advskew); + printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n", + state, carpr.carpr_carpdev, carpr.carpr_vhid, + carpr.carpr_advbase, carpr.carpr_advskew); } =20 return; =20 } =20 =2Dvoid =2Dsetcarp_passwd(const char *val, int d, int s, const struct afswtch *afp) +static +DECL_CMD_FUNC(setcarp_passwd, val, d) { struct carpreq carpr; =20 @@ -105,8 +99,8 @@ return; } =20 =2Dvoid =2Dsetcarp_vhid(const char *val, int d, int s, const struct afswtch *afp) +static +DECL_CMD_FUNC(setcarp_vhid, val, d) { int vhid; struct carpreq carpr; @@ -130,8 +124,8 @@ return; } =20 =2Dvoid =2Dsetcarp_advskew(const char *val, int d, int s, const struct afswtch *afp) +static +DECL_CMD_FUNC(setcarp_advskew, val, d) { int advskew; struct carpreq carpr; @@ -152,8 +146,8 @@ return; } =20 =2Dvoid =2Dsetcarp_advbase(const char *val, int d, int s, const struct afswtch *afp) +static +DECL_CMD_FUNC(setcarp_advbase, val, d) { int advbase; struct carpreq carpr; @@ -174,11 +168,51 @@ return; } =20 +static +DECL_CMD_FUNC(setcarp_carpdev, val, d) +{ + struct carpreq carpr; + + memset((char *)&carpr, 0, sizeof(struct carpreq)); + ifr.ifr_data =3D (caddr_t)&carpr; + + if (ioctl(s, SIOCGVH, (caddr_t)&ifr) =3D=3D -1) + err(1, "SIOCGVH"); + + strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev)); + + if (ioctl(s, SIOCSVH, (caddr_t)&ifr) =3D=3D -1) + err(1, "SIOCSVH"); + + return; +} + +static +DECL_CMD_FUNC(setcarp_unsetcarpdev, val, d) +{ + struct carpreq carpr; + + memset((char *)&carpr, 0, sizeof(struct carpreq)); + ifr.ifr_data =3D (caddr_t)&carpr; + + if (ioctl(s, SIOCGVH, (caddr_t)&ifr) =3D=3D -1) + err(1, "SIOCGVH"); + + memset(carpr.carpr_carpdev, 0, sizeof(carpr.carpr_carpdev)); + + if (ioctl(s, SIOCSVH, (caddr_t)&ifr) =3D=3D -1) + err(1, "SIOCSVH"); + + return; +} + static struct cmd carp_cmds[] =3D { DEF_CMD_ARG("advbase", setcarp_advbase), DEF_CMD_ARG("advskew", setcarp_advskew), DEF_CMD_ARG("pass", setcarp_passwd), DEF_CMD_ARG("vhid", setcarp_vhid), + DEF_CMD_ARG("carpdev", setcarp_carpdev), + DEF_CMD_OPTARG("-carpdev", setcarp_unsetcarpdev), }; static struct afswtch af_carp =3D { .af_name =3D "af_carp", =2D-- //depot/vendor/freebsd/src/sys/net/ethernet.h 2007/05/29 12:43:19 +++ //depot/user/mlaier/carp2/sys/net/ethernet.h 2007/09/19 18:47:18 @@ -380,6 +380,7 @@ extern void ether_ifattach(struct ifnet *, const u_int8_t *); extern void ether_ifdetach(struct ifnet *); extern int ether_ioctl(struct ifnet *, u_long, caddr_t); +extern void ether_input(struct ifnet *, struct mbuf *); extern int ether_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); extern int ether_output_frame(struct ifnet *, struct mbuf *); =2D-- //depot/vendor/freebsd/src/sys/net/if.c 2007/07/27 12:03:05 +++ //depot/user/mlaier/carp2/sys/net/if.c 2007/09/19 18:47:18 @@ -1309,8 +1309,7 @@ pfctlinput(PRC_IFDOWN, ifa->ifa_addr); if_qflush(&ifp->if_snd); #ifdef DEV_CARP =2D if (ifp->if_carp) =2D carp_carpdev_state(ifp->if_carp); + carp_carpdev_state(ifp); #endif rt_ifmsg(ifp); } @@ -1333,8 +1332,7 @@ if (fam =3D=3D PF_UNSPEC || (fam =3D=3D ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFUP, ifa->ifa_addr); #ifdef DEV_CARP =2D if (ifp->if_carp) =2D carp_carpdev_state(ifp->if_carp); + carp_carpdev_state(ifp); #endif rt_ifmsg(ifp); #ifdef INET6 @@ -1386,8 +1384,7 @@ IFP2AC(ifp)->ac_netgraph !=3D NULL) (*ng_ether_link_state_p)(ifp, link_state); #ifdef DEV_CARP =2D if (ifp->if_carp) =2D carp_carpdev_state(ifp->if_carp); + carp_carpdev_state(ifp); #endif if (ifp->if_bridge) { KASSERT(bstp_linkstate_p !=3D NULL,("if_bridge bstp not loaded!")); =2D-- //depot/vendor/freebsd/src/sys/net/if_ethersubr.c 2007/09/14 07:03:02 +++ //depot/user/mlaier/carp2/sys/net/if_ethersubr.c 2007/10/05 22:40:49 @@ -153,6 +153,9 @@ u_char esrc[ETHER_ADDR_LEN], edst[ETHER_ADDR_LEN]; struct ether_header *eh; struct pf_mtag *t; +#ifdef DEV_CARP + struct ifnet *ifp0 =3D ifp; +#endif int loop_copy =3D 1; int hlen; /* link layer header length */ =20 @@ -162,6 +165,19 @@ senderr(error); #endif =20 +#ifdef DEV_CARP + if (ifp->if_type =3D=3D IFT_CARP) { + struct ifaddr *ifa; + + if (dst !=3D NULL && ifp->if_link_state =3D=3D LINK_STATE_UP && + (ifa =3D ifa_ifwithaddr(dst)) !=3D NULL && + ifa->ifa_ifp =3D=3D ifp) + return (looutput(ifp, m, dst, rt0)); + + ifp =3D ifp->if_carpdev; + } +#endif + if (ifp->if_flags & IFF_MONITOR) senderr(ENETDOWN); if (!((ifp->if_flags & IFF_UP) && @@ -172,7 +188,11 @@ switch (dst->sa_family) { #ifdef INET case AF_INET: +#ifdef DEV_CARP + error =3D arpresolve(ifp0, rt0, m, dst, edst); +#else error =3D arpresolve(ifp, rt0, m, dst, edst); +#endif if (error) return (error =3D=3D EWOULDBLOCK ? 0 : error); type =3D htons(ETHERTYPE_IP); @@ -293,6 +313,14 @@ (void)memcpy(eh->ether_shost, IF_LLADDR(ifp), sizeof(eh->ether_shost)); =20 +#ifdef DEV_CARP + if (ifp0 !=3D ifp && ifp0->if_type =3D=3D IFT_CARP) { + /* XXX: LINK1 */ + (void)memcpy(eh->ether_shost, IF_LLADDR(ifp0), + sizeof(eh->ether_shost)); + } +#endif + /* * If a simplex interface, and the packet is being sent to our * Ethernet address or a broadcast address, loopback a copy. @@ -351,12 +379,6 @@ return (error); } =20 =2D#ifdef DEV_CARP =2D if (ifp->if_carp && =2D (error =3D carp_output(ifp, m, dst, NULL))) =2D goto bad; =2D#endif =2D /* Handle ng_ether(4) processing, if any */ if (IFP2AC(ifp)->ac_netgraph !=3D NULL) { KASSERT(ng_ether_output_p !=3D NULL, @@ -506,7 +528,7 @@ * Process a received Ethernet packet; the packet is in the * mbuf chain m with the ethernet header at the front. */ =2Dstatic void +void ether_input(struct ifnet *ifp, struct mbuf *m) { struct ether_header *eh; @@ -658,19 +680,15 @@ } =20 #ifdef DEV_CARP =2D /* =2D * Clear M_PROMISC on frame so that carp(4) will see it when the =2D * mbuf flows up to Layer 3. =2D * FreeBSD's implementation of carp(4) uses the inprotosw =2D * to dispatch IPPROTO_CARP. carp(4) also allocates its own =2D * Ethernet addresses of the form 00:00:5e:00:01:xx, which =2D * is outside the scope of the M_PROMISC test below. =2D * TODO: Maintain a hash table of ethernet addresses other than =2D * ether_dhost which may be active on this ifp. =2D */ =2D if (ifp->if_carp && carp_forus(ifp->if_carp, eh->ether_dhost)) { =2D m->m_flags &=3D ~M_PROMISC; =2D } else + if (ifp->if_carp) { + if (ifp->if_type !=3D IFT_CARP && (carp_input(m) =3D=3D 0)) + return; + else if (ifp->if_type =3D=3D IFT_CARP && + /* XXX: LINK2 */ + m->m_flags & (M_BCAST | M_MCAST) && + !bcmp(IFP2AC(ifp), eh->ether_dhost, ETHER_ADDR_LEN)) + m->m_flags &=3D ~(M_BCAST | M_MCAST); + } #endif { /* =2D-- //depot/vendor/freebsd/src/sys/net/if_loop.c 2007/02/09 00:13:58 +++ //depot/user/mlaier/carp2/sys/net/if_loop.c 2007/09/19 18:47:18 @@ -99,8 +99,6 @@ =20 int loioctl(struct ifnet *, u_long, caddr_t); static void lortrequest(int, struct rtentry *, struct rt_addrinfo *); =2Dint looutput(struct ifnet *ifp, struct mbuf *m, =2D struct sockaddr *dst, struct rtentry *rt); static int lo_clone_create(struct if_clone *, int, caddr_t); static void lo_clone_destroy(struct ifnet *); =20 =2D-- //depot/vendor/freebsd/src/sys/net/if_var.h 2007/05/16 18:42:49 +++ //depot/user/mlaier/carp2/sys/net/if_var.h 2007/09/19 18:47:18 @@ -131,7 +131,12 @@ */ struct knlist if_klist; /* events attached to this if */ int if_pcount; /* number of promiscuous listeners */ =2D struct carp_if *if_carp; /* carp interface structure */ + union { + struct carp_if *carp_s; + struct ifnet *carp_d; + } if_carp_ptr; +#define if_carp if_carp_ptr.carp_s +#define if_carpdev if_carp_ptr.carp_d struct bpf_if *if_bpf; /* packet filter structure */ u_short if_index; /* numeric abbreviation for this if */ short if_timer; /* time 'til if_watchdog called */ @@ -691,6 +696,8 @@ struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *); =20 int if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen); +int looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rt); =20 typedef void *if_com_alloc_t(u_char type, struct ifnet *ifp); typedef void if_com_free_t(void *com, u_char type); =2D-- //depot/vendor/freebsd/src/sys/netinet/if_ether.c 2007/10/07 20:49:19 +++ //depot/user/mlaier/carp2/sys/netinet/if_ether.c 2007/10/10 00:26:22 @@ -110,7 +110,6 @@ &arp_proxyall, 0, "Enable proxy ARP for all suitable requests"); =20 static void arp_init(void); =2Dstatic void arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *); static void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, u_char *); static void arpintr(struct mbuf *); @@ -144,7 +143,7 @@ /* * Parallel to llc_rtrequest. */ =2Dstatic void +void arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) { struct sockaddr *gate; @@ -608,7 +607,8 @@ itaddr.s_addr =3D=3D ia->ia_addr.sin_addr.s_addr) goto match; #ifdef DEV_CARP =2D if (ifp->if_carp !=3D NULL && + if (ifp->if_type !=3D IFT_CARP && ifp->if_carp !=3D NULL && + ia->ia_ifp->if_type =3D=3D IFT_CARP && carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && itaddr.s_addr =3D=3D ia->ia_addr.sin_addr.s_addr) { carp_match =3D 1; @@ -679,6 +679,7 @@ && (ifp->if_type !=3D IFT_CARP || !carp_match) #endif ) { +// printf("arp: %s %d\n", ifp->if_xname, carp_match); if (log_arp_wrong_iface) log(LOG_ERR, "arp: %s is on %s but got reply from %*D on %s\n", inet_ntoa(isaddr), =2D-- //depot/vendor/freebsd/src/sys/netinet/if_ether.h 2005/02/22 13:06:15 +++ //depot/user/mlaier/carp2/sys/netinet/if_ether.h 2007/09/19 18:47:18 @@ -113,6 +113,7 @@ struct mbuf *m, struct sockaddr *dst, u_char *desten); void arp_ifinit(struct ifnet *, struct ifaddr *); void arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *); +void arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *); #endif =20 #endif =2D-- //depot/vendor/freebsd/src/sys/netinet/in_proto.c 2007/10/07 20:49:19 +++ //depot/user/mlaier/carp2/sys/netinet/in_proto.c 2007/10/10 00:26:22 @@ -318,7 +318,7 @@ .pr_domain =3D &inetdomain, .pr_protocol =3D IPPROTO_CARP, .pr_flags =3D PR_ATOMIC|PR_ADDR, =2D .pr_input =3D carp_input, + .pr_input =3D carp_proto_input, .pr_output =3D (pr_output_t*)rip_output, .pr_ctloutput =3D rip_ctloutput, .pr_usrreqs =3D &rip_usrreqs =2D-- //depot/vendor/freebsd/src/sys/netinet/ip_carp.c 2007/10/07 20:49:19 +++ //depot/user/mlaier/carp2/sys/netinet/ip_carp.c 2007/10/27 20:24:21 @@ -92,11 +92,9 @@ =20 struct carp_softc { struct ifnet *sc_ifp; /* Interface clue */ =2D struct ifnet *sc_carpdev; /* Pointer to parent interface */ =2D struct in_ifaddr *sc_ia; /* primary iface address */ +#define sc_carpdev sc_ifp->if_carpdev struct ip_moptions sc_imo; #ifdef INET6 =2D struct in6_ifaddr *sc_ia6; /* primary iface address v6 */ struct ip6_moptions sc_im6o; #endif /* INET6 */ TAILQ_ENTRY(carp_softc) sc_list; @@ -159,7 +157,7 @@ struct mtx vhif_mtx; }; =20 =2D/* Get carp_if from softc. Valid after carp_set_addr{,6}. */ +/* Get carp_if from softc. Valid after carp_set_{addr[6],ifp}. */ #define SC2CIF(sc) ((struct carp_if *)(sc)->sc_carpdev->if_carp) =20 /* lock per carp_if queue */ @@ -190,7 +188,7 @@ static int carp_hmac_verify(struct carp_softc *, u_int32_t *, unsigned char *); static void carp_setroute(struct carp_softc *, int); =2Dstatic void carp_input_c(struct mbuf *, struct carp_header *, sa_family_= t); +static void carp_proto_input_c(struct mbuf *, struct carp_header *, sa_fam= ily_t); static int carp_clone_create(struct if_clone *, int, caddr_t); static void carp_clone_destroy(struct ifnet *); static void carpdetach(struct carp_softc *, int); @@ -203,7 +201,7 @@ static void carp_master_down(void *); static void carp_master_down_locked(struct carp_softc *); static int carp_ioctl(struct ifnet *, u_long, caddr_t); =2Dstatic int carp_looutput(struct ifnet *, struct mbuf *, struct sockaddr = *, +static int carp_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); static void carp_start(struct ifnet *); static void carp_setrun(struct carp_softc *, sa_family_t); @@ -212,13 +210,16 @@ enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING }; =20 static void carp_multicast_cleanup(struct carp_softc *); +static int carp_set_ifp(struct carp_softc *, struct ifnet *); static int carp_set_addr(struct carp_softc *, struct sockaddr_in *); +static int carp_join_multicast(struct carp_softc *); static int carp_del_addr(struct carp_softc *, struct sockaddr_in *); static void carp_carpdev_state_locked(struct carp_if *); static void carp_sc_state_locked(struct carp_softc *); #ifdef INET6 static void carp_send_na(struct carp_softc *); static int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *); +static int carp_join_multicast6(struct carp_softc *); static int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *); static void carp_multicast6_cleanup(struct carp_softc *); #endif @@ -247,9 +248,9 @@ #endif =20 if (sc->sc_carpdev) =2D CARP_SCLOCK(sc); + CARP_SCLOCK_ASSERT(sc); =20 =2D /* XXX: possible race here */ + /* XXX: possible race here - really? */ =20 /* compute ipad from key */ bzero(sc->sc_pad, sizeof(sc->sc_pad)); @@ -285,8 +286,6 @@ for (i =3D 0; i < sizeof(sc->sc_pad); i++) sc->sc_pad[i] ^=3D 0x36 ^ 0x5c; =20 =2D if (sc->sc_carpdev) =2D CARP_SCUNLOCK(sc); } =20 static void @@ -334,13 +333,106 @@ TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family =3D=3D AF_INET && sc->sc_carpdev !=3D NULL) { =2D int count =3D carp_addrcount( =2D (struct carp_if *)sc->sc_carpdev->if_carp, =2D ifatoia(ifa), CARP_COUNT_MASTER); + int count =3D 0, error; + struct sockaddr sa; + struct rtentry *rt; + struct radix_node_head *rnh; + struct radix_node *rn; + struct rt_addrinfo info; + int hr_otherif, nr_ourif; + + /* + * Avoid screwing with the routes if there are other + * carp interfaces which are master and have the same + * address. + */ + if (sc->sc_carpdev !=3D NULL && + sc->sc_carpdev->if_carp !=3D NULL) { + count =3D carp_addrcount( + (struct carp_if *)sc->sc_carpdev->if_carp, + ifatoia(ifa), CARP_COUNT_MASTER); + if ((cmd =3D=3D RTM_ADD && count !=3D 1) || + (cmd =3D=3D RTM_DELETE && count !=3D 0)) + continue; + } + + /* Remove the existing host route, if any */ + bzero(&info, sizeof(info)); + info.rti_info[RTAX_DST] =3D ifa->ifa_addr; + info.rti_flags =3D RTF_HOST; + error =3D rtrequest1(RTM_DELETE, &info, NULL); + rt_missmsg(RTM_DELETE, &info, info.rti_flags, error); + + /* Check for our address on another interface */ + /* XXX cries for proper API */ + rnh =3D rt_tables[ifa->ifa_addr->sa_family]; + RADIX_NODE_HEAD_LOCK(rnh); + rn =3D rnh->rnh_matchaddr(ifa->ifa_addr, rnh); + rt =3D (struct rtentry *)rn; + hr_otherif =3D (rt && rt->rt_ifp !=3D sc->sc_ifp && + rt->rt_flags & (RTF_CLONING|RTF_WASCLONED)); + + /* Check for a network route on our interface */ + bcopy(ifa->ifa_addr, &sa, sizeof(sa)); + satosin(&sa)->sin_addr.s_addr =3D satosin(ifa->ifa_netmask + )->sin_addr.s_addr & satosin(&sa)->sin_addr.s_addr; + rn =3D rnh->rnh_lookup(&sa, ifa->ifa_netmask, rnh); + rt =3D (struct rtentry *)rn; + nr_ourif =3D (rt && rt->rt_ifp =3D=3D sc->sc_ifp); + RADIX_NODE_HEAD_UNLOCK(rnh); + + switch (cmd) { + case RTM_ADD: + if (hr_otherif) { + ifa->ifa_rtrequest =3D NULL; + ifa->ifa_flags &=3D ~RTF_CLONING; + bzero(&info, sizeof(info)); + info.rti_info[RTAX_DST] =3D + ifa->ifa_addr; + info.rti_info[RTAX_GATEWAY] =3D + ifa->ifa_addr; + info.rti_flags =3D RTF_UP | RTF_HOST; + error =3D rtrequest1(RTM_ADD, &info, + NULL); + rt_missmsg(RTM_ADD, &info, + info.rti_flags, error); + } + if (!hr_otherif || nr_ourif || !rt) { + if (nr_ourif && !(rt->rt_flags & + RTF_CLONING)) { + bzero(&info, sizeof(info)); + info.rti_info[RTAX_DST] =3D &sa; + info.rti_info[RTAX_NETMASK] =3D + ifa->ifa_netmask; + error =3D rtrequest1(RTM_DELETE, + &info, NULL); + rt_missmsg(RTM_DELETE, &info, + info.rti_flags, error); + } + + ifa->ifa_rtrequest =3D arp_rtrequest; + ifa->ifa_flags |=3D RTF_CLONING; =20 =2D if ((cmd =3D=3D RTM_ADD && count =3D=3D 1) || =2D (cmd =3D=3D RTM_DELETE && count =3D=3D 0)) =2D rtinit(ifa, cmd, RTF_UP | RTF_HOST); + bzero(&info, sizeof(info)); + info.rti_info[RTAX_DST] =3D &sa; + info.rti_info[RTAX_GATEWAY] =3D + ifa->ifa_addr; + info.rti_info[RTAX_NETMASK] =3D + ifa->ifa_netmask; + error =3D rtrequest1(RTM_ADD, &info, + NULL); + if (error =3D=3D 0) + ifa->ifa_flags |=3D IFA_ROUTE; + rt_missmsg(RTM_ADD, &info, + info.rti_flags, error); + } + break; + case RTM_DELETE: + break; + default: + break; + } + break; } #ifdef INET6 if (ifa->ifa_addr->sa_family =3D=3D AF_INET6) { @@ -360,6 +452,7 @@ =20 struct carp_softc *sc; struct ifnet *ifp; + static const u_char eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ =20 MALLOC(sc, struct carp_softc *, sizeof(*sc), M_CARP, M_WAITOK|M_ZERO); ifp =3D SC2IFP(sc) =3D if_alloc(IFT_ETHER); @@ -391,16 +484,13 @@ =09 ifp->if_softc =3D sc; if_initname(ifp, CARP_IFNAME, unit); =2D ifp->if_mtu =3D ETHERMTU; =2D ifp->if_flags =3D IFF_LOOPBACK; + ether_ifattach(ifp, eaddr); + ifp->if_flags =3D IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl =3D carp_ioctl; =2D ifp->if_output =3D carp_looutput; + ifp->if_output =3D carp_output; ifp->if_start =3D carp_start; ifp->if_type =3D IFT_CARP; ifp->if_snd.ifq_maxlen =3D ifqmaxlen; =2D ifp->if_hdrlen =3D 0; =2D if_attach(ifp); =2D bpfattach(SC2IFP(sc), DLT_NULL, sizeof(u_int32_t)); mtx_lock(&carp_mtx); LIST_INSERT_HEAD(&carpif_list, sc, sc_next); mtx_unlock(&carp_mtx); @@ -503,7 +593,7 @@ * but it seems more efficient this way or not possible otherwise. */ void =2Dcarp_input(struct mbuf *m, int hlen) +carp_proto_input(struct mbuf *m, int hlen) { struct ip *ip =3D mtod(m, struct ip *); struct carp_header *ch; @@ -517,9 +607,9 @@ } =20 /* check if received on a valid carp interface */ =2D if (m->m_pkthdr.rcvif->if_carp =3D=3D NULL) { + if (m->m_pkthdr.rcvif->if_type !=3D IFT_CARP) { carpstats.carps_badif++; =2D CARP_LOG("carp_input: packet received on non-carp " + CARP_LOG("carp_proto_input: packet received on non-carp " "interface: %s\n", m->m_pkthdr.rcvif->if_xname); m_freem(m); @@ -529,7 +619,7 @@ /* verify that the IP TTL is 255. */ if (ip->ip_ttl !=3D CARP_DFLTTL) { carpstats.carps_badttl++; =2D CARP_LOG("carp_input: received ttl %d !=3D 255i on %s\n", + CARP_LOG("carp_proto_input: received ttl %d !=3D 255i on %s\n", ip->ip_ttl, m->m_pkthdr.rcvif->if_xname); m_freem(m); @@ -540,7 +630,7 @@ =20 if (m->m_pkthdr.len < iplen + sizeof(*ch)) { carpstats.carps_badlen++; =2D CARP_LOG("carp_input: received len %zd < " + CARP_LOG("carp_proto_input: received len %zd < " "sizeof(struct carp_header)\n", m->m_len - sizeof(struct ip)); m_freem(m); @@ -550,7 +640,7 @@ if (iplen + sizeof(*ch) < m->m_len) { if ((m =3D m_pullup(m, iplen + sizeof(*ch))) =3D=3D NULL) { carpstats.carps_hdrops++; =2D CARP_LOG("carp_input: pullup failed\n"); + CARP_LOG("carp_proto_input: pullup failed\n"); return; } ip =3D mtod(m, struct ip *); @@ -564,7 +654,7 @@ len =3D iplen + sizeof(*ch); if (len > m->m_pkthdr.len) { carpstats.carps_badlen++; =2D CARP_LOG("carp_input: packet too short %d on %s\n", + CARP_LOG("carp_proto_input: packet too short %d on %s\n", m->m_pkthdr.len, m->m_pkthdr.rcvif->if_xname); m_freem(m); @@ -582,19 +672,19 @@ m->m_data +=3D iplen; if (carp_cksum(m, len - iplen)) { carpstats.carps_badsum++; =2D CARP_LOG("carp_input: checksum failed on %s\n", + CARP_LOG("carp_proto_input: checksum failed on %s\n", m->m_pkthdr.rcvif->if_xname); m_freem(m); return; } m->m_data -=3D iplen; =20 =2D carp_input_c(m, ch, AF_INET); + carp_proto_input_c(m, ch, AF_INET); } =20 #ifdef INET6 int =2Dcarp6_input(struct mbuf **mp, int *offp, int proto) +carp6_proto_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m =3D *mp; struct ip6_hdr *ip6 =3D mtod(m, struct ip6_hdr *); @@ -609,9 +699,9 @@ } =20 /* check if received on a valid carp interface */ =2D if (m->m_pkthdr.rcvif->if_carp =3D=3D NULL) { + if (m->m_pkthdr.rcvif->if_type !=3D IFT_CARP) { carpstats.carps_badif++; =2D CARP_LOG("carp6_input: packet received on non-carp " + CARP_LOG("carp6_proto_input: packet received on non-carp " "interface: %s\n", m->m_pkthdr.rcvif->if_xname); m_freem(m); @@ -621,7 +711,7 @@ /* verify that the IP TTL is 255 */ if (ip6->ip6_hlim !=3D CARP_DFLTTL) { carpstats.carps_badttl++; =2D CARP_LOG("carp6_input: received ttl %d !=3D 255 on %s\n", + CARP_LOG("carp6_proto_input: received ttl %d !=3D 255 on %s\n", ip6->ip6_hlim, m->m_pkthdr.rcvif->if_xname); m_freem(m); @@ -633,7 +723,7 @@ IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch)); if (ch =3D=3D NULL) { carpstats.carps_badlen++; =2D CARP_LOG("carp6_input: packet size %u too small\n", len); + CARP_LOG("carp6_proto_input: packet size %u too small\n", len); return (IPPROTO_DONE); } =20 @@ -642,22 +732,22 @@ m->m_data +=3D *offp; if (carp_cksum(m, sizeof(*ch))) { carpstats.carps_badsum++; =2D CARP_LOG("carp6_input: checksum failed, on %s\n", + CARP_LOG("carp6_proto_input: checksum failed, on %s\n", m->m_pkthdr.rcvif->if_xname); m_freem(m); return (IPPROTO_DONE); } m->m_data -=3D *offp; =20 =2D carp_input_c(m, ch, AF_INET6); + carp_proto_input_c(m, ch, AF_INET6); return (IPPROTO_DONE); } #endif /* INET6 */ =20 static void =2Dcarp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) +carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) { =2D struct ifnet *ifp =3D m->m_pkthdr.rcvif; + struct ifnet *ifp =3D m->m_pkthdr.rcvif->if_carpdev; struct carp_softc *sc; u_int64_t tmp_counter; struct timeval sc_tv, ch_tv; @@ -793,9 +883,6 @@ static int carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header = *ch) { =2D struct m_tag *mtag; =2D struct ifnet *ifp =3D SC2IFP(sc); =2D if (sc->sc_init_counter) { /* this could also be seconds since unix epoch */ sc->sc_counter =3D arc4random(); @@ -809,16 +896,6 @@ =20 carp_hmac_generate(sc, ch->carp_counter, ch->carp_md); =20 =2D /* Tag packet for carp_output */ =2D mtag =3D m_tag_get(PACKET_TAG_CARP, sizeof(struct ifnet *), M_NOWAIT); =2D if (mtag =3D=3D NULL) { =2D m_freem(m); =2D SC2IFP(sc)->if_oerrors++; =2D return (ENOMEM); =2D } =2D bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *)); =2D m_tag_prepend(m, mtag); =2D return (0); } =20 @@ -859,6 +936,8 @@ struct carp_header *ch_ptr; struct mbuf *m; int len, advbase, advskew; + struct ifaddr *ifa; + struct sockaddr sa; =20 CARP_SCLOCK_ASSERT(sc); =20 @@ -887,7 +966,7 @@ ch.carp_cksum =3D 0; =20 #ifdef INET =2D if (sc->sc_ia) { + if (sc->sc_naddrs) { struct ip *ip; =20 MGETHDR(m, M_DONTWAIT, MT_HEADER); @@ -916,7 +995,15 @@ ip->ip_ttl =3D CARP_DFLTTL; ip->ip_p =3D IPPROTO_CARP; ip->ip_sum =3D 0; =2D ip->ip_src.s_addr =3D sc->sc_ia->ia_addr.sin_addr.s_addr; + + bzero(&sa, sizeof(sa)); + sa.sa_family =3D AF_INET; + ifa =3D ifaof_ifpforaddr(&sa, SC2IFP(sc)); + if (ifa =3D=3D NULL) + ip->ip_src.s_addr =3D 0; + else + ip->ip_src.s_addr =3D + ifatoia(ifa)->ia_addr.sin_addr.s_addr; ip->ip_dst.s_addr =3D htonl(INADDR_CARP_GROUP); =20 ch_ptr =3D (struct carp_header *)(&ip[1]); @@ -959,7 +1046,7 @@ } #endif /* INET */ #ifdef INET6 =2D if (sc->sc_ia6) { + if (sc->sc_naddrs6) { struct ip6_hdr *ip6; =20 MGETHDR(m, M_DONTWAIT, MT_HEADER); @@ -983,8 +1070,15 @@ ip6->ip6_vfc |=3D IPV6_VERSION; ip6->ip6_hlim =3D CARP_DFLTTL; ip6->ip6_nxt =3D IPPROTO_CARP; =2D bcopy(&sc->sc_ia6->ia_addr.sin6_addr, &ip6->ip6_src, =2D sizeof(struct in6_addr)); + + bzero(&sa, sizeof(sa)); + sa.sa_family =3D AF_INET6; + ifa =3D ifaof_ifpforaddr(&sa, SC2IFP(sc)); + if (ifa =3D=3D NULL) + bzero(&ip6->ip6_src, sizeof(struct in6_addr)); + else + bcopy(ifatoia6(ifa)->ia_addr.sin6_addr.s6_addr, + &ip6->ip6_src, sizeof(struct in6_addr)); /* set the multicast destination */ =20 ip6->ip6_dst.s6_addr16[0] =3D htons(0xff02); @@ -1058,7 +1152,7 @@ continue; =20 /* arprequest(sc->sc_carpdev, &in, &in, IF_LLADDR(sc->sc_ifp)); */ =2D arp_ifinit2(sc->sc_carpdev, ifa, IF_LLADDR(sc->sc_ifp)); + arp_ifinit2(SC2IFP(sc), ifa, IF_LLADDR(sc->sc_ifp)); =20 DELAY(1000); /* XXX */ } @@ -1119,9 +1213,17 @@ struct carp_softc *vh; int index, count =3D 0; struct ifaddr *ifa; + char iastr[INET_ADDRSTRLEN]; + char isstr[INET_ADDRSTRLEN]; + =20 CARP_LOCK(cif); =20 + inet_ntoa_r(ia->ia_addr.sin_addr, iastr); + inet_ntoa_r(*isaddr, isstr); + printf("carp_iamatch(%s, %s, %s, ...)\n", cif->vhif_ifp->if_xname, + iastr, isstr); + if (carp_opts[CARPCTL_ARPBALANCE]) { /* * XXX proof of concept implementation. @@ -1173,8 +1275,11 @@ ia->ia_ifp =3D=3D SC2IFP(vh) && vh->sc_state =3D=3D MASTER) { *enaddr =3D IF_LLADDR(vh->sc_ifp); + printf("found: %s\n", vh->sc_ifp->if_xname); CARP_UNLOCK(cif); return (1); + } else { + printf("not: %s\n", vh->sc_ifp->if_xname); } } } @@ -1211,7 +1316,6 @@ void * carp_macmatch6(void *v, struct mbuf *m, const struct in6_addr *taddr) { =2D struct m_tag *mtag; struct carp_if *cif =3D v; struct carp_softc *sc; struct ifaddr *ifa; @@ -1223,18 +1327,6 @@ &ifatoia6(ifa)->ia_addr.sin6_addr) && (SC2IFP(sc)->if_flags & IFF_UP) && (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING)) { =2D struct ifnet *ifp =3D SC2IFP(sc); =2D mtag =3D m_tag_get(PACKET_TAG_CARP, =2D sizeof(struct ifnet *), M_NOWAIT); =2D if (mtag =3D=3D NULL) { =2D /* better a bit than nothing */ =2D CARP_UNLOCK(cif); =2D return (IF_LLADDR(sc->sc_ifp)); =2D } =2D bcopy(&ifp, (caddr_t)(mtag + 1), =2D sizeof(struct ifnet *)); =2D m_tag_prepend(m, mtag); =2D CARP_UNLOCK(cif); return (IF_LLADDR(sc->sc_ifp)); } @@ -1423,15 +1515,116 @@ #endif =20 static int +carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp) +{ + struct carp_if *cif =3D NULL, *ncif =3D NULL; + struct carp_softc *vr, *after =3D NULL; + int myself =3D 0, error =3D 0; + + if (ifp =3D=3D sc->sc_carpdev) + return (0); + + if (ifp !=3D NULL) { + if ((ifp->if_flags & IFF_MULTICAST) =3D=3D 0) + return (ENODEV); + if (ifp->if_type =3D=3D IFT_CARP) + return (EINVAL); + + if (ifp->if_carp =3D=3D NULL) { + MALLOC(ncif, struct carp_if *, sizeof(*ncif), M_CARP, + M_WAITOK|M_ZERO); + if (!ncif) + return (ENOBUFS); + if ((error =3D ifpromisc(ifp, 1))) { + FREE(ncif, M_CARP); + return (error); + } + } else { + cif =3D (struct carp_if *)ifp->if_carp; + CARP_LOCK(cif); + TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) + if (vr !=3D sc && vr->sc_vhid =3D=3D sc->sc_vhid) { + CARP_UNLOCK(cif); + return (EINVAL); + } + } + + /* detach from old interface */ + if (sc->sc_carpdev !=3D NULL) { + CARP_SCLOCK(sc); + carpdetach(sc, 1); + } + + if (sc->sc_naddrs !=3D 0 && + (error =3D carp_join_multicast(sc)) !=3D 0) + goto cleanup; +#ifdef INET6 + if (sc->sc_naddrs6 !=3D 0 && + (error =3D carp_join_multicast6(sc)) !=3D 0) { + carp_multicast_cleanup(sc); + goto cleanup; + } +#endif + + /* attach carp glue to physical interface */ + if (ncif !=3D NULL) { + CARP_LOCK_INIT(ncif); + CARP_LOCK(ncif); + ncif->vhif_ifp =3D ifp; + TAILQ_INIT(&ncif->vhif_vrs); + TAILQ_INSERT_HEAD(&ncif->vhif_vrs, sc, sc_list); + ncif->vhif_nvrs++; + ifp->if_carp =3D ncif; + CARP_UNLOCK(ncif); + } else { + cif =3D (struct carp_if *)ifp->if_carp; + TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { + if (vr =3D=3D sc) + myself =3D 1; + if (vr->sc_vhid < sc->sc_vhid) + after =3D vr; + } + if (!myself) { + if (after =3D=3D NULL) { + TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, + sc_list); + } else { + TAILQ_INSERT_AFTER(&cif->vhif_vrs, + after, sc, sc_list); + } + cif->vhif_nvrs++; + } + CARP_UNLOCK(cif); + } + + sc->sc_carpdev =3D ifp; + if (sc->sc_naddrs || sc->sc_naddrs6) + sc->sc_ifp->if_flags |=3D IFF_UP; + carp_carpdev_state(ifp); + } else { + CARP_SCLOCK(sc); + carpdetach(sc, 1); + SC2IFP(sc)->if_flags &=3D ~IFF_UP; + SC2IFP(sc)->if_drv_flags &=3D ~IFF_DRV_RUNNING; + } + + return (0); +cleanup: + if (ncif) + FREE(ncif, M_CARP); + else + CARP_UNLOCK(cif); + + return (error); +} + +static int carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) { =2D struct ifnet *ifp; =2D struct carp_if *cif; + struct ifnet *ifp =3D sc->sc_carpdev; struct in_ifaddr *ia, *ia_if; =2D struct ip_moptions *imo =3D &sc->sc_imo; =2D struct in_addr addr; u_long iaddr =3D htonl(sin->sin_addr.s_addr); =2D int own, error; + int error; =20 if (sin->sin_addr.s_addr =3D=3D 0) { if (!(SC2IFP(sc)->if_flags & IFF_UP)) @@ -1443,7 +1636,7 @@ } =20 /* we have to do it by hands to check we won't match on us */ =2D ia_if =3D NULL; own =3D 0; + ia_if =3D NULL; TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { /* and, yeah, we need a multicast-capable iface too */ if (ia->ia_ifp !=3D SC2IFP(sc) && @@ -1451,106 +1644,65 @@ (iaddr & ia->ia_subnetmask) =3D=3D ia->ia_subnet) { if (!ia_if) ia_if =3D ia; =2D if (sin->sin_addr.s_addr =3D=3D =2D ia->ia_addr.sin_addr.s_addr) =2D own++; } } =20 =2D if (!ia_if) =2D return (EADDRNOTAVAIL); =2D =2D ia =3D ia_if; =2D ifp =3D ia->ia_ifp; =2D =2D if (ifp =3D=3D NULL || (ifp->if_flags & IFF_MULTICAST) =3D=3D 0 || =2D (imo->imo_multicast_ifp && imo->imo_multicast_ifp !=3D ifp)) =2D return (EADDRNOTAVAIL); =2D =2D if (imo->imo_num_memberships =3D=3D 0) { =2D addr.s_addr =3D htonl(INADDR_CARP_GROUP); =2D if ((imo->imo_membership[0] =3D in_addmulti(&addr, ifp)) =3D=3D NULL) =2D return (ENOBUFS); =2D imo->imo_num_memberships++; =2D imo->imo_multicast_ifp =3D ifp; =2D imo->imo_multicast_ttl =3D CARP_DFLTTL; =2D imo->imo_multicast_loop =3D 0; =2D } =2D =2D if (!ifp->if_carp) { =2D =2D MALLOC(cif, struct carp_if *, sizeof(*cif), M_CARP, =2D M_WAITOK|M_ZERO); =2D if (!cif) { =2D error =3D ENOBUFS; =2D goto cleanup; + if (ia_if) { + ia =3D ia_if; + if (ifp) { + if (ifp !=3D ia->ia_ifp) + return (EADDRNOTAVAIL); + } else { + ifp =3D ia->ia_ifp; } =2D if ((error =3D ifpromisc(ifp, 1))) { =2D FREE(cif, M_CARP); =2D goto cleanup; =2D } =2D =09 =2D CARP_LOCK_INIT(cif); =2D CARP_LOCK(cif); =2D cif->vhif_ifp =3D ifp; =2D TAILQ_INIT(&cif->vhif_vrs); =2D ifp->if_carp =3D cif; =2D =2D } else { =2D struct carp_softc *vr; =2D =2D cif =3D (struct carp_if *)ifp->if_carp; =2D CARP_LOCK(cif); =2D TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) =2D if (vr !=3D sc && vr->sc_vhid =3D=3D sc->sc_vhid) { =2D CARP_UNLOCK(cif); =2D error =3D EINVAL; =2D goto cleanup; =2D } } =2D sc->sc_ia =3D ia; =2D sc->sc_carpdev =3D ifp; =20 =2D { /* XXX prevent endless loop if already in queue */ =2D struct carp_softc *vr, *after =3D NULL; =2D int myself =3D 0; =2D cif =3D (struct carp_if *)ifp->if_carp; + if ((error =3D carp_set_ifp(sc, ifp))) + return (error); =20 =2D /* XXX: cif should not change, right? So we still hold the lock */ =2D CARP_LOCK_ASSERT(cif); + if (sc->sc_carpdev =3D=3D NULL) + return (EADDRNOTAVAIL); =20 =2D TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { =2D if (vr =3D=3D sc) =2D myself =3D 1; =2D if (vr->sc_vhid < sc->sc_vhid) =2D after =3D vr; + CARP_SCLOCK(sc); + if (sc->sc_naddrs =3D=3D 0 && (error =3D carp_join_multicast(sc)) !=3D 0)= { + CARP_SCUNLOCK(sc); + return (error); } =20 =2D if (!myself) { =2D /* We're trying to keep things in order */ =2D if (after =3D=3D NULL) { =2D TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list); =2D } else { =2D TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list); =2D } =2D cif->vhif_nvrs++; =2D } =2D } =2D sc->sc_naddrs++; SC2IFP(sc)->if_flags |=3D IFF_UP; =2D if (own) =2D sc->sc_advskew =3D 0; carp_sc_state_locked(sc); carp_setrun(sc, 0); + CARP_SCUNLOCK(sc); + + return (0); + +/* + * XXX: cleanup multi? + * cleanup: + * return (error); + */ +} + +static int +carp_join_multicast(struct carp_softc *sc) +{ + struct ip_moptions *imo =3D &sc->sc_imo; + struct in_addr addr; + + KASSERT(imo->imo_num_memberships =3D=3D 0, + ("carp_join_multicast: leftover multicast memberships")); =20 =2D CARP_UNLOCK(cif); + addr.s_addr =3D htonl(INADDR_CARP_GROUP); + if ((imo->imo_membership[0] =3D + in_addmulti(&addr, SC2IFP(sc))) =3D=3D NULL) + return (ENOBUFS); + imo->imo_num_memberships++; + imo->imo_multicast_ifp =3D SC2IFP(sc); + imo->imo_multicast_ttl =3D CARP_DFLTTL; + imo->imo_multicast_loop =3D 0; =20 return (0); =2D =2Dcleanup: =2D in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); =2D return (error); } =20 static int @@ -1587,12 +1739,8 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) { struct ifnet *ifp; =2D struct carp_if *cif; struct in6_ifaddr *ia, *ia_if; =2D struct ip6_moptions *im6o =3D &sc->sc_im6o; =2D struct in6_multi_mship *imm; =2D struct in6_addr in6; =2D int own, error; + int own; =20 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { if (!(SC2IFP(sc)->if_flags & IFF_UP)) @@ -1633,114 +1781,74 @@ ifp =3D ia->ia_ifp; =20 if (ifp =3D=3D NULL || (ifp->if_flags & IFF_MULTICAST) =3D=3D 0 || =2D (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp !=3D ifp)) + (sc->sc_im6o.im6o_multicast_ifp && + sc->sc_im6o.im6o_multicast_ifp !=3D ifp)) return (EADDRNOTAVAIL); =20 =2D if (!sc->sc_naddrs6) { =2D im6o->im6o_multicast_ifp =3D ifp; + sc->sc_carpdev =3D ifp; =20 =2D /* join CARP multicast address */ =2D bzero(&in6, sizeof(in6)); =2D in6.s6_addr16[0] =3D htons(0xff02); =2D in6.s6_addr8[15] =3D 0x12; =2D if (in6_setscope(&in6, ifp, NULL) !=3D 0) =2D goto cleanup; =2D if ((imm =3D in6_joingroup(ifp, &in6, &error, 0)) =3D=3D NULL) =2D goto cleanup; =2D LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain); + sc->sc_naddrs6++; + SC2IFP(sc)->if_flags |=3D IFF_UP; + if (own) + sc->sc_advskew =3D 0; + carp_sc_state_locked(sc); + carp_setrun(sc, 0); =20 =2D /* join solicited multicast address */ =2D bzero(&in6, sizeof(in6)); =2D in6.s6_addr16[0] =3D htons(0xff02); =2D in6.s6_addr32[1] =3D 0; =2D in6.s6_addr32[2] =3D htonl(1); =2D in6.s6_addr32[3] =3D sin6->sin6_addr.s6_addr32[3]; =2D in6.s6_addr8[12] =3D 0xff; =2D if (in6_setscope(&in6, ifp, NULL) !=3D 0) =2D goto cleanup; =2D if ((imm =3D in6_joingroup(ifp, &in6, &error, 0)) =3D=3D NULL) =2D goto cleanup; =2D LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain); =2D } + return (0); =20 =2D if (!ifp->if_carp) { =2D MALLOC(cif, struct carp_if *, sizeof(*cif), M_CARP, =2D M_WAITOK|M_ZERO); =2D if (!cif) { =2D error =3D ENOBUFS; =2D goto cleanup; =2D } =2D if ((error =3D ifpromisc(ifp, 1))) { =2D FREE(cif, M_CARP); =2D goto cleanup; =2D } +/* XXX: + * cleanup: + * * clean up multicast memberships * + * if (!sc->sc_naddrs6) { + * while (!LIST_EMPTY(&im6o->im6o_memberships)) { + * imm =3D LIST_FIRST(&im6o->im6o_memberships); + * LIST_REMOVE(imm, i6mm_chain); + * in6_leavegroup(imm); + * } + * } + * return (error); + */ +} =20 =2D CARP_LOCK_INIT(cif); =2D CARP_LOCK(cif); =2D cif->vhif_ifp =3D ifp; =2D TAILQ_INIT(&cif->vhif_vrs); =2D ifp->if_carp =3D cif; +static int +carp_join_multicast6(struct carp_softc *sc) +{ + struct ip6_moptions *im6o =3D &sc->sc_im6o; + struct in6_multi_mship *imm, *imm2; + struct in6_addr in6; + int error =3D 0; =20 =2D } else { =2D struct carp_softc *vr; + /* join CARP multicast address */ + bzero(&in6, sizeof(in6)); + in6.s6_addr16[0] =3D htons(0xff02); + in6.s6_addr8[15] =3D 0x12; + if ((error =3D in6_setscope(&in6, sc->sc_carpdev, NULL)) !=3D 0) + return (error); + if ((imm =3D in6_joingroup(sc->sc_carpdev, &in6, &error, 0)) =3D=3D NULL) + return (error); =20 =2D cif =3D (struct carp_if *)ifp->if_carp; =2D CARP_LOCK(cif); =2D TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) =2D if (vr !=3D sc && vr->sc_vhid =3D=3D sc->sc_vhid) { =2D CARP_UNLOCK(cif); =2D error =3D EINVAL; =2D goto cleanup; =2D } + /* join solicited multicast address */ + bzero(&in6, sizeof(in6)); + in6.s6_addr16[0] =3D htons(0xff02); + in6.s6_addr32[1] =3D 0; + in6.s6_addr32[2] =3D htonl(1); + in6.s6_addr32[3] =3D 0; /* XXX: sin6->sin6_addr.s6_addr32[3]; */ + in6.s6_addr8[12] =3D 0xff; + if ((error =3D in6_setscope(&in6, sc->sc_carpdev, NULL)) !=3D 0) { + in6_leavegroup(imm); + return (error); } =2D sc->sc_ia6 =3D ia; =2D sc->sc_carpdev =3D ifp; =2D =2D { /* XXX prevent endless loop if already in queue */ =2D struct carp_softc *vr, *after =3D NULL; =2D int myself =3D 0; =2D cif =3D (struct carp_if *)ifp->if_carp; =2D CARP_LOCK_ASSERT(cif); =2D =2D TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { =2D if (vr =3D=3D sc) =2D myself =3D 1; =2D if (vr->sc_vhid < sc->sc_vhid) =2D after =3D vr; + if ((imm2 =3D in6_joingroup(sc->sc_carpdev, &in6, &error, 0)) =3D=3D NULL= ) { + in6_leavegroup(imm); + return (error); } =20 =2D if (!myself) { =2D /* We're trying to keep things in order */ =2D if (after =3D=3D NULL) { =2D TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list); =2D } else { =2D TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list); =2D } =2D cif->vhif_nvrs++; =2D } =2D } + im6o->im6o_multicast_ifp =3D sc->sc_carpdev; =20 =2D sc->sc_naddrs6++; =2D SC2IFP(sc)->if_flags |=3D IFF_UP; =2D if (own) =2D sc->sc_advskew =3D 0; =2D carp_sc_state_locked(sc); =2D carp_setrun(sc, 0); + LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain); + LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2, i6mm_chain); =20 =2D CARP_UNLOCK(cif); =2D return (0); =2D =2Dcleanup: =2D /* clean up multicast memberships */ =2D if (!sc->sc_naddrs6) { =2D while (!LIST_EMPTY(&im6o->im6o_memberships)) { =2D imm =3D LIST_FIRST(&im6o->im6o_memberships); =2D LIST_REMOVE(imm, i6mm_chain); =2D in6_leavegroup(imm); =2D } =2D } =2D return (error); } =20 static int @@ -1786,7 +1894,8 @@ struct ifaddr *ifa; struct ifreq *ifr; struct ifaliasreq *ifra; =2D int locked =3D 0, error =3D 0; + struct ifnet *cdev =3D NULL; + int locked =3D 0, error =3D 0, changed =3D 0; =20 ifa =3D (struct ifaddr *)addr; ifra =3D (struct ifaliasreq *)addr; @@ -1794,12 +1903,12 @@ =20 switch (cmd) { case SIOCSIFADDR: + case SIOCAIFADDR: + changed++; switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: SC2IFP(sc)->if_flags |=3D IFF_UP; =2D bcopy(ifa->ifa_addr, ifa->ifa_dstaddr, =2D sizeof(struct sockaddr)); error =3D carp_set_addr(sc, satosin(ifa->ifa_addr)); break; #endif /* INET */ @@ -1815,29 +1924,8 @@ } break; =20 =2D case SIOCAIFADDR: =2D switch (ifa->ifa_addr->sa_family) { =2D#ifdef INET =2D case AF_INET: =2D SC2IFP(sc)->if_flags |=3D IFF_UP; =2D bcopy(ifa->ifa_addr, ifa->ifa_dstaddr, =2D sizeof(struct sockaddr)); =2D error =3D carp_set_addr(sc, satosin(&ifra->ifra_addr)); =2D break; =2D#endif /* INET */ =2D#ifdef INET6 =2D case AF_INET6: =2D SC2IFP(sc)->if_flags |=3D IFF_UP; =2D error =3D carp_set_addr6(sc, satosin6(&ifra->ifra_addr)); =2D break; =2D#endif /* INET6 */ =2D default: =2D error =3D EAFNOSUPPORT; =2D break; =2D } =2D break; =2D case SIOCDIFADDR: + changed++; switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: @@ -1881,6 +1969,14 @@ if ((error =3D copyin(ifr->ifr_data, &carpr, sizeof carpr))) break; error =3D 1; + changed++; + if (carpr.carpr_carpdev[0] !=3D '\0' && + (cdev =3D ifunit(carpr.carpr_carpdev)) =3D=3D NULL) { + error =3D EINVAL; + break; + } + if ((error =3D carp_set_ifp(sc, cdev))) + break; if (sc->sc_carpdev) { locked =3D 1; CARP_SCLOCK(sc); @@ -1959,64 +2055,37 @@ if (error =3D=3D 0) bcopy(sc->sc_key, carpr.carpr_key, sizeof(carpr.carpr_key)); + if (sc->sc_carpdev !=3D NULL) + strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname, + CARPDEVNAMSIZ); error =3D copyout(&carpr, ifr->ifr_data, sizeof(carpr)); break; =20 + case SIOCADDMULTI: + case SIOCDELMULTI: + /* TODO: tell carpdev */ + break; + default: error =3D EINVAL; } =20 + if (changed) { + if (!locked && sc->sc_carpdev) { + /* XXX: This really shouldn't happen */ + CARP_SCLOCK(sc); + locked =3D 1; + } + carp_hmac_prepare(sc); + } + if (locked) CARP_SCUNLOCK(sc); =20 =2D carp_hmac_prepare(sc); =2D return (error); } =20 /* =2D * XXX: this is looutput. We should eventually use it from there. =2D */ =2Dstatic int =2Dcarp_looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, =2D struct rtentry *rt) =2D{ =2D u_int32_t af; =2D =2D M_ASSERTPKTHDR(m); /* check if we have the packet header */ =2D =2D if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { =2D m_freem(m); =2D return (rt->rt_flags & RTF_BLACKHOLE ? 0 : =2D rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); =2D } =2D =2D ifp->if_opackets++; =2D ifp->if_obytes +=3D m->m_pkthdr.len; =2D =2D /* BPF writes need to be handled specially. */ =2D if (dst->sa_family =3D=3D AF_UNSPEC) { =2D bcopy(dst->sa_data, &af, sizeof(af)); =2D dst->sa_family =3D af; =2D } =2D =2D#if 1 /* XXX */ =2D switch (dst->sa_family) { =2D case AF_INET: =2D case AF_INET6: =2D case AF_IPX: =2D case AF_APPLETALK: =2D break; =2D default: =2D printf("carp_looutput: af=3D%d unexpected\n", dst->sa_family); =2D m_freem(m); =2D return (EAFNOSUPPORT); =2D } =2D#endif =2D return(if_simloop(ifp, m, dst->sa_family, 0)); =2D} =2D =2D/* * Start output on carp interface. This function should never be called. */ static void @@ -2027,80 +2096,83 @@ #endif } =20 =2Dint +static int carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, struct rtentry *rt) { =2D struct m_tag *mtag; =2D struct carp_softc *sc; =2D struct ifnet *carp_ifp; + struct carp_softc *sc =3D ifp->if_softc; + + if (sc->sc_carpdev !=3D NULL && sc->sc_state =3D=3D MASTER) + return (sc->sc_carpdev->if_output(ifp, m, sa, rt)); + else { + m_freem(m); + return (ENETUNREACH); + } +} + +struct ifnet * +carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src) +{ + struct carp_if *cif =3D (struct carp_if *)v; + struct carp_softc *vh; + u_int8_t *ena; =20 =2D if (!sa) =2D return (0); + if (src) + ena =3D (u_int8_t *)&eh->ether_shost; + else + ena =3D (u_int8_t *)&eh->ether_dhost; =20 =2D switch (sa->sa_family) { =2D#ifdef INET =2D case AF_INET: =2D break; =2D#endif /* INET */ =2D#ifdef INET6 =2D case AF_INET6: =2D break; =2D#endif /* INET6 */ =2D default: =2D return (0); + TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { + if ((vh->sc_ifp->if_flags & (IFF_UP)) !=3D (IFF_UP)) + continue; + if ((vh->sc_state =3D=3D MASTER /* || vh->sc_ifp->if_flags & IFF_LINK0 *= /) + && !bcmp(ena, IF_LLADDR(vh->sc_ifp), ETHER_ADDR_LEN)) + return (vh->sc_ifp); } + return (NULL); +} =20 =2D mtag =3D m_tag_find(m, PACKET_TAG_CARP, NULL); =2D if (mtag =3D=3D NULL) =2D return (0); +int +carp_input(struct mbuf *m) +{ + struct ether_header *eh; + struct carp_if *cif =3D (struct carp_if *)m->m_pkthdr.rcvif->if_carp; + struct ifnet *ifp; =20 =2D bcopy(mtag + 1, &carp_ifp, sizeof(struct ifnet *)); =2D sc =3D carp_ifp->if_softc; + eh =3D mtod(m, struct ether_header *); =20 =2D /* Set the source MAC address to Virtual Router MAC Address */ =2D switch (ifp->if_type) { =2D case IFT_ETHER: =2D case IFT_L2VLAN: { =2D struct ether_header *eh; + if ((ifp =3D carp_ourether(cif, eh, m->m_pkthdr.rcvif->if_type, 0))) + ; + else if (m->m_flags & (M_BCAST|M_MCAST)) { + struct carp_softc *vh; + struct mbuf *m0; =20 =2D eh =3D mtod(m, struct ether_header *); =2D eh->ether_shost[0] =3D 0; =2D eh->ether_shost[1] =3D 0; =2D eh->ether_shost[2] =3D 0x5e; =2D eh->ether_shost[3] =3D 0; =2D eh->ether_shost[4] =3D 1; =2D eh->ether_shost[5] =3D sc->sc_vhid; + /* + * XXX Should really check the list of multicast addresses + * for each CARP interface _before_ copying. + */ + TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { + m0 =3D m_dup(m, M_DONTWAIT); + if (m0 =3D=3D NULL) + continue; + m0->m_pkthdr.rcvif =3D vh->sc_ifp; + ether_input(vh->sc_ifp, m0); } =2D break; =2D case IFT_FDDI: { =2D struct fddi_header *fh; + return (1); + } + + if (ifp =3D=3D NULL) + return (1); + + m->m_pkthdr.rcvif =3D ifp; =20 =2D fh =3D mtod(m, struct fddi_header *); =2D fh->fddi_shost[0] =3D 0; =2D fh->fddi_shost[1] =3D 0; =2D fh->fddi_shost[2] =3D 0x5e; =2D fh->fddi_shost[3] =3D 0; =2D fh->fddi_shost[4] =3D 1; =2D fh->fddi_shost[5] =3D sc->sc_vhid; =2D } =2D break; =2D case IFT_ISO88025: { =2D struct iso88025_header *th; =2D th =3D mtod(m, struct iso88025_header *); =2D th->iso88025_shost[0] =3D 3; =2D th->iso88025_shost[1] =3D 0; =2D th->iso88025_shost[2] =3D 0x40 >> (sc->sc_vhid - 1); =2D th->iso88025_shost[3] =3D 0x40000 >> (sc->sc_vhid - 1); =2D th->iso88025_shost[4] =3D 0; =2D th->iso88025_shost[5] =3D 0; =2D } =2D break; =2D default: =2D printf("%s: carp is not supported for this interface type\n", =2D ifp->if_xname); =2D return (EOPNOTSUPP); =2D } +#if 0 /* XXX: BPF */ + if (ifp->if_bpf) + bpf_mtap_hdr(ifp->if_bpf, (char *)&eh, ETHER_HDR_LEN, m, + BPF_DIRECTION_IN); +#endif + ifp->if_ipackets++; + ether_input(ifp, m); =20 return (0); } @@ -2131,9 +2203,14 @@ } =20 void =2Dcarp_carpdev_state(void *v) +carp_carpdev_state(struct ifnet *ifp) { =2D struct carp_if *cif =3D v; + struct carp_if *cif; + + if (ifp->if_type =3D=3D IFT_CARP || ifp->if_carp =3D=3D NULL) + return; + + cif =3D ifp->if_carp; =20 CARP_LOCK(cif); carp_carpdev_state_locked(cif); =2D-- //depot/vendor/freebsd/src/sys/netinet/ip_carp.h 2006/12/01 18:41:18 +++ //depot/user/mlaier/carp2/sys/netinet/ip_carp.h 2007/09/19 18:47:18 @@ -117,6 +117,13 @@ uint64_t carps_preempt; /* if enabled, preemptions */ }; =20 +#define CARPDEVNAMSIZ 16 +#ifdef IFNAMSIZ +#if CARPDEVNAMSIZ !=3D IFNAMSIZ +#error +#endif +#endif + /* * Configuration structure for SIOCSVH SIOCGVH */ @@ -128,6 +135,7 @@ int carpr_advskew; int carpr_advbase; unsigned char carpr_key[CARP_KEY_LEN]; + char carpr_carpdev[CARPDEVNAMSIZ]; }; #define SIOCSVH _IOWR('i', 245, struct ifreq) #define SIOCGVH _IOWR('i', 246, struct ifreq) @@ -152,15 +160,15 @@ } =20 #ifdef _KERNEL =2Dvoid carp_carpdev_state(void *); =2Dvoid carp_input (struct mbuf *, int); =2Dint carp6_input (struct mbuf **, int *, int); =2Dint carp_output (struct ifnet *, struct mbuf *, struct sockaddr *, =2D struct rtentry *); =2Dint carp_iamatch (void *, struct in_ifaddr *, struct in_addr *, +void carp_carpdev_state(struct ifnet *); +void carp_proto_input(struct mbuf *, int); +int carp6_proto_input(struct mbuf **, int *, int); +int carp_iamatch(void *, 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 *); =2Dstruct ifnet *carp_forus (void *, void *); +struct ifnet *carp_forus(void *, void *); +struct ifnet *carp_ourether(void *, struct ether_header *, u_char, int); +int carp_input(struct mbuf *); #endif #endif /* _IP_CARP_H */ =2D-- //depot/vendor/freebsd/src/sys/netinet6/in6_proto.c 2007/07/05 16:32:= 05 +++ //depot/user/mlaier/carp2/sys/netinet6/in6_proto.c 2007/09/19 18:47:18 @@ -319,7 +319,7 @@ .pr_domain =3D &inet6domain, .pr_protocol =3D IPPROTO_CARP, .pr_flags =3D PR_ATOMIC|PR_ADDR, =2D .pr_input =3D carp6_input, + .pr_input =3D carp6_proto_input, .pr_output =3D rip6_output, .pr_ctloutput =3D rip6_ctloutput, .pr_usrreqs =3D &rip6_usrreqs --Boundary-01=_nl6IH3bgJTGz2kl-- --nextPart3069786.LU2bnx6mTt Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.4 (FreeBSD) iD8DBQBHI6ltXyyEoT62BG0RAqlmAJ9HUKDcYxSN3tUzsl9duGj/rkIorwCfWrJf vceD/SVvMTCFgK5xLyH9S5s= =XJkp -----END PGP SIGNATURE----- --nextPart3069786.LU2bnx6mTt--