diff options
author | Marco Pfatschbacher <mpf@cvs.openbsd.org> | 2007-03-18 23:23:18 +0000 |
---|---|---|
committer | Marco Pfatschbacher <mpf@cvs.openbsd.org> | 2007-03-18 23:23:18 +0000 |
commit | 6f9929b6c6550b6c1afc1f5a1a5e4e3ee079857f (patch) | |
tree | 7b53d8b777e07c5f80672a4209bba5256148b33e | |
parent | 1cddb68d501e88a56b636de082738e5483715814 (diff) |
Add IP load balancing support for carp(4).
This provides a similar functionality as ARP balancing,
but also works for traffic that comes across routers.
IPv6 is supported as well.
The configuration scheme will change as soon we have sth better.
Also add support for changing the MAC address on carp(4)
interfaces. (code from mcbride)
Tested by pyr@ and reyk@
OK mcbride@
-rw-r--r-- | sys/net/if.c | 3 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 22 | ||||
-rw-r--r-- | sys/netinet/if_ether.c | 11 | ||||
-rw-r--r-- | sys/netinet/ip_carp.c | 330 | ||||
-rw-r--r-- | sys/netinet/ip_carp.h | 5 | ||||
-rw-r--r-- | sys/netinet/ip_icmp.c | 30 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 25 | ||||
-rw-r--r-- | sys/netinet6/icmp6.c | 17 | ||||
-rw-r--r-- | sys/netinet6/ip6_input.c | 24 | ||||
-rw-r--r-- | sys/netinet6/nd6_nbr.c | 11 |
10 files changed, 376 insertions, 102 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 165f044713a..7231c29be4b 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.155 2007/02/14 00:53:48 jsg Exp $ */ +/* $OpenBSD: if.c,v 1.156 2007/03/18 23:23:17 mpf Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -1329,6 +1329,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) return (EINVAL); switch (ifp->if_type) { case IFT_ETHER: + case IFT_CARP: case IFT_FDDI: case IFT_XETHER: case IFT_ISO88025: diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index cdf78cb50c1..45d030e548a 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.105 2006/12/07 18:15:29 reyk Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.106 2007/03/18 23:23:17 mpf Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -401,7 +401,8 @@ ether_output(ifp0, m0, dst, rt0) sizeof(eh->ether_shost)); #if NCARP > 0 - if (ifp0 != ifp && ifp0->if_type == IFT_CARP) { + if (ifp0 != ifp && ifp0->if_type == IFT_CARP && + !(ifp0->if_flags & IFF_LINK1)) { bcopy((caddr_t)((struct arpcom *)ifp0)->ac_enaddr, (caddr_t)eh->ether_shost, sizeof(eh->ether_shost)); } @@ -595,10 +596,19 @@ ether_input(ifp, eh, m) #endif /* NVLAN > 0 */ #if NCARP > 0 - if (ifp->if_carp && ifp->if_type != IFT_CARP && - (carp_input(m, (u_int8_t *)&eh->ether_shost, - (u_int8_t *)&eh->ether_dhost, eh->ether_type) == 0)) - return; + if (ifp->if_carp) { + if (ifp->if_type != IFT_CARP && + (carp_input(m, (u_int8_t *)&eh->ether_shost, + (u_int8_t *)&eh->ether_dhost, eh->ether_type) == 0)) + return; + /* Always clear multicast flags if received on a carp address */ + else if (ifp->if_type == IFT_CARP && + ifp->if_flags & IFF_LINK2 && + m->m_flags & (M_BCAST|M_MCAST) && + !bcmp(((struct arpcom *)ifp)->ac_enaddr, + (caddr_t)eh->ether_dhost, ETHER_ADDR_LEN)) + m->m_flags &= ~(M_BCAST|M_MCAST); + } #endif /* NCARP > 0 */ ac = (struct arpcom *)ifp; diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 4d99bb1e294..cf9c1662d81 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ether.c,v 1.66 2007/03/16 16:58:40 deraadt Exp $ */ +/* $OpenBSD: if_ether.c,v 1.67 2007/03/18 23:23:17 mpf Exp $ */ /* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */ /* @@ -720,7 +720,14 @@ reply: ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ eh = (struct ether_header *)sa.sa_data; bcopy(ea->arp_tha, eh->ether_dhost, sizeof(eh->ether_dhost)); - bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost)); +#if NCARP > 0 + if (ac->ac_if.if_type == IFT_CARP && ac->ac_if.if_flags & IFF_LINK1) + bcopy(((struct arpcom *)ac->ac_if.if_carpdev)->ac_enaddr, + eh->ether_shost, sizeof(eh->ether_shost)); + else +#endif + bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost)); + eh->ether_type = htons(ETHERTYPE_ARP); sa.sa_family = pseudo_AF_HDRCMPLT; sa.sa_len = sizeof(sa); diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 61bd993ba19..d2719316dc9 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.c,v 1.132 2006/12/13 09:01:59 itojun Exp $ */ +/* $OpenBSD: ip_carp.c,v 1.133 2007/03/18 23:23:17 mpf Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -126,6 +126,8 @@ struct carp_softc { int sc_sendad_success; #define CARP_SENDAD_MIN_SUCCESS 3 + char sc_carplladdr[ETHER_ADDR_LEN]; + char sc_curlladdr[ETHER_ADDR_LEN]; int sc_vhid; int sc_advskew; int sc_naddrs; @@ -141,6 +143,8 @@ struct carp_softc { SHA1_CTX sc_sha1[HMAC_MAX]; u_int32_t sc_hashkey[2]; + u_int32_t sc_lsmask; /* load sharing mask */ + int sc_lscount; /* # load sharing interfaces (max 32) */ struct timeout sc_ad_tmo; /* advertisement timeout */ struct timeout sc_md_tmo; /* master down timeout */ @@ -192,9 +196,8 @@ void carp_ifgroup_ioctl(struct ifnet *, u_long, caddr_t); void carp_start(struct ifnet *); void carp_setrun(struct carp_softc *, sa_family_t); void carp_set_state(struct carp_softc *, int); -int carp_addrcount(struct carp_if *, struct in_ifaddr *, int); -enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING }; - +int carp_addrcount(struct carp_if *, struct ifaddr *, int); +enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING, CARP_COUNT_LINK0 }; void carp_multicast_cleanup(struct carp_softc *); int carp_set_ifp(struct carp_softc *, struct ifnet *); void carp_set_enaddr(struct carp_softc *); @@ -213,6 +216,7 @@ int carp_ether_addmulti(struct carp_softc *, struct ifreq *); int carp_ether_delmulti(struct carp_softc *, struct ifreq *); void carp_ether_purgemulti(struct carp_softc *); int carp_group_demote_count(struct carp_softc *); +void carp_update_lsmask(struct carp_softc *); struct if_clone carp_cloner = IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy); @@ -265,6 +269,10 @@ carp_hmac_prepare_ctx(struct carp_softc *sc, u_int8_t ctx) sc->sc_hashkey[1] = kmd[2] ^ kmd[3]; /* the rest of the precomputation */ + if (bcmp(sc->sc_ac.ac_enaddr, &sc->sc_carplladdr, ETHER_ADDR_LEN) != 0) + SHA1Update(&sc->sc_sha1[ctx], sc->sc_ac.ac_enaddr, + ETHER_ADDR_LEN); + SHA1Update(&sc->sc_sha1[ctx], (void *)&vhid, sizeof(vhid)); /* Hash the addresses from smallest to largest, not interface order */ @@ -379,7 +387,7 @@ carp_setroute(struct carp_softc *sc, int cmd) sc->sc_carpdev->if_carp != NULL) { count = carp_addrcount( (struct carp_if *)sc->sc_carpdev->if_carp, - ifatoia(ifa), CARP_COUNT_MASTER); + ifa, CARP_COUNT_MASTER); if ((cmd == RTM_ADD && count != 1) || (cmd == RTM_DELETE && count != 0)) continue; @@ -832,7 +840,6 @@ carp_clone_create(ifc, unit) if_attach(ifp); if_alloc_sadl(ifp); - carp_set_enaddr(sc); LIST_INIT(&sc->sc_ac.ac_multiaddrs); #if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN); @@ -1175,6 +1182,10 @@ carp_send_arp(struct carp_softc *sc) if (ifa->ifa_addr->sa_family != AF_INET) continue; + if (carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp, + ifa, CARP_COUNT_LINK0)) + continue; + in = ifatoia(ifa)->ia_addr.sin_addr.s_addr; arprequest(sc->sc_carpdev, &in, &in, sc->sc_ac.ac_enaddr); DELAY(1000); /* XXX */ @@ -1242,26 +1253,131 @@ carp_hash(struct carp_softc *sc, u_char *src) } int -carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type) +carp_addrcount(struct carp_if *cif, struct ifaddr *ifa0, int type) { struct carp_softc *vh; struct ifaddr *ifa; int count = 0; TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { - if ((type == CARP_COUNT_RUNNING && - (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == - (IFF_UP|IFF_RUNNING)) || - (type == CARP_COUNT_MASTER && vh->sc_state == MASTER)) { + switch (type) { + case CARP_COUNT_RUNNING: + if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)) + continue; + break; + case CARP_COUNT_MASTER: + if (vh->sc_state != MASTER) + continue; + break; + case CARP_COUNT_LINK0: + if (!(vh->sc_if.if_flags & IFF_LINK0) || + (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)) + continue; + break; + } + TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family == AF_INET && + ifa0->ifa_addr->sa_family == AF_INET && + ifatoia(ifa0)->ia_addr.sin_addr.s_addr == + ifatoia(ifa)->ia_addr.sin_addr.s_addr) + count++; +#ifdef INET6 + if (ifa->ifa_addr->sa_family == AF_INET6 && + ifa0->ifa_addr->sa_family == AF_INET6 && + IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa0), IFA_IN6(ifa))) + count++; +#endif + } + } + return (count); +} + +void +carp_update_lsmask(struct carp_softc *sc) +{ + struct carp_softc *curvh, *vh, *sc0 = NULL; + struct carp_if *cif; + struct ifaddr *ifa, *ifa0 = NULL; + int cur, last, count, found; + + if (!sc->sc_carpdev) + return; + cif = (struct carp_if *)sc->sc_carpdev->if_carp; + + /* + * Take the first IPv4 address from the LINK0 carp interface + * to determine the load sharing group. + * Fallback on the first IPv6 address. + */ + TAILQ_FOREACH(sc0, &cif->vhif_vrs, sc_list) + if (sc0->sc_if.if_flags & IFF_LINK0) + break; + if (sc0 == NULL) + return; + + TAILQ_FOREACH(ifa0, &sc0->sc_if.if_addrlist, ifa_list) + if (ifa0->ifa_addr->sa_family == AF_INET) + break; +#ifdef INET6 + if (ifa0 == NULL) + TAILQ_FOREACH(ifa0, &sc0->sc_if.if_addrlist, ifa_list) + if (ifa0->ifa_addr->sa_family == AF_INET6 && + !IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa0))) + break; +#endif + if (ifa0 == NULL) + return; + /* + * Calculate the load sharing mask w/ all carp interfaces + * that share the first address of the LINK0 interface. + * Sort by virtual host ID. + */ + sc0->sc_lsmask = 0; + cur = 0; + curvh = NULL; + count = 0; + do { + found = 0; + last = cur; + cur = 255; + TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { + if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)) + continue; TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family == AF_INET && - ia->ia_addr.sin_addr.s_addr == + ifa0->ifa_addr->sa_family == AF_INET && + ifatoia(ifa0)->ia_addr.sin_addr.s_addr == ifatoia(ifa)->ia_addr.sin_addr.s_addr) - count++; + break; +#ifdef INET6 + if (ifa->ifa_addr->sa_family == AF_INET6 && + ifa0->ifa_addr->sa_family == AF_INET6 && + IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa0), IFA_IN6(ifa))) + break; +#endif + } + if (ifa && vh->sc_vhid > last && vh->sc_vhid < cur) { + cur = vh->sc_vhid; + curvh = vh; + found++; } } - } - return (count); + if (found) { + if (curvh->sc_state == MASTER && + count < sizeof(sc0->sc_lsmask) * 8) + sc0->sc_lsmask |= 1 << count; + count++; + } + } while (found); + + sc0->sc_lscount = count; + if (count == 0) + return; + + CARP_LOG(sc, ("carp_update_lsmask: %x", sc0->sc_lsmask)) } int @@ -1270,6 +1386,15 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src, { struct carp_softc *sc = ia->ia_ifp->if_softc; + /* + * If the asked address is found on a LINK0 interface + * don't answer the arp reply unless we are MASTER on it. + */ + if (!(sc->sc_if.if_flags & IFF_LINK0) && sc->sc_carpdev && + carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp, + (struct ifaddr *)ia, CARP_COUNT_LINK0)) + return (0); + if (carp_opts[CARPCTL_ARPBALANCE]) { /* * We use the source ip to decide which virtual host should @@ -1278,11 +1403,11 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src, * the floor. */ - /* Count the elegible carp interfaces with this address */ + /* Count the eligible carp interfaces with this address */ if (*count == 0) *count = carp_addrcount( (struct carp_if *)ia->ia_ifp->if_carpdev->if_carp, - ia, CARP_COUNT_RUNNING); + (struct ifaddr *)ia, CARP_COUNT_RUNNING); /* This should never happen, but... */ if (*count == 0) @@ -1301,24 +1426,24 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src, } #ifdef INET6 -struct ifaddr * -carp_iamatch6(void *v, struct in6_addr *taddr) +int +carp_iamatch6(struct ifnet *ifp, struct ifaddr *ifa) { - struct carp_if *cif = v; - struct carp_softc *vh; - struct ifaddr *ifa; + struct carp_softc *sc = ifp->if_softc; - TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { - TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) { - if (IN6_ARE_ADDR_EQUAL(taddr, - &ifatoia6(ifa)->ia_addr.sin6_addr) && - ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == - (IFF_UP|IFF_RUNNING)) && vh->sc_state == MASTER) - return (ifa); - } - } + /* + * If the asked address is found on a LINK0 interface + * don't answer the arp request unless we are MASTER on it. + */ + if (!(sc->sc_if.if_flags & IFF_LINK0) && sc->sc_carpdev && + carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp, + ifa, CARP_COUNT_LINK0)) + return (0); - return (NULL); + if (sc->sc_state == MASTER) + return (1); + + return (0); } #endif /* INET6 */ @@ -1334,28 +1459,14 @@ carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src) else ena = (u_int8_t *)&eh->ether_dhost; - switch (iftype) { - case IFT_ETHER: - case IFT_FDDI: - if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1) - return (NULL); - break; - case IFT_ISO88025: - if (ena[0] != 3 || ena[1] || ena[4] || ena[5]) - return (NULL); - break; - default: - return (NULL); - break; - } - - TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) - if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == - (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER && - !bcmp(ena, vh->sc_ac.ac_enaddr, - ETHER_ADDR_LEN)) + TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { + if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)) + continue; + if ((vh->sc_state == MASTER || vh->sc_if.if_flags & IFF_LINK0) + && !bcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN)) return (&vh->sc_if); - + } return (NULL); } @@ -1370,7 +1481,9 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) bcopy(dhost, &eh.ether_dhost, sizeof(eh.ether_dhost)); eh.ether_type = etype; - if (m->m_flags & (M_BCAST|M_MCAST)) { + if ((ifp = 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; @@ -1388,7 +1501,6 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) return (1); } - ifp = carp_ourether(cif, &eh, m->m_pkthdr.rcvif->if_type, 0); if (ifp == NULL) return (1); @@ -1405,6 +1517,35 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) return (0); } +int +carp_lsdrop(struct mbuf *m, sa_family_t af, u_int32_t *src, u_int32_t *dst) +{ + struct carp_softc *sc = m->m_pkthdr.rcvif->if_softc; + int match; + u_int32_t fold; + + /* + * Never drop carp advertisements. + * XXX Bad idea to pass all broadcast / multicast traffic? + */ + if (m->m_flags & (M_BCAST|M_MCAST)) + return (0); + + fold = src[0] ^ dst[0]; +#ifdef INET6 + if (af == AF_INET6) { + int i; + for (i = 1; i < 4; i++) + fold ^= src[i] ^ dst[i]; + } +#endif + if (sc->sc_lscount == 0) /* just to be safe */ + return (1); + match = (1 << (ntohl(fold) % sc->sc_lscount)) & sc->sc_lsmask; + + return (!match); +} + void carp_master_down(void *v) { @@ -1627,31 +1768,45 @@ carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp) void carp_set_enaddr(struct carp_softc *sc) { - if (sc->sc_vhid == -1 || !sc->sc_carpdev) { - bzero(&sc->sc_ac.ac_enaddr, sizeof (sc->sc_ac.ac_enaddr)); + if (sc->sc_vhid != -1 && sc->sc_carpdev) { /* XXX detach ipv6 link-local address? */ - } else if (sc->sc_carpdev && sc->sc_carpdev->if_type == IFT_ISO88025) { - sc->sc_ac.ac_enaddr[0] = 3; - sc->sc_ac.ac_enaddr[1] = 0; - sc->sc_ac.ac_enaddr[2] = 0x40 >> (sc->sc_vhid - 1); - sc->sc_ac.ac_enaddr[3] = 0x40000 >> (sc->sc_vhid - 1); - sc->sc_ac.ac_enaddr[4] = 0; - sc->sc_ac.ac_enaddr[5] = 0; - } else { - sc->sc_ac.ac_enaddr[0] = 0; - sc->sc_ac.ac_enaddr[1] = 0; - sc->sc_ac.ac_enaddr[2] = 0x5e; - sc->sc_ac.ac_enaddr[3] = 0; - sc->sc_ac.ac_enaddr[4] = 1; - sc->sc_ac.ac_enaddr[5] = sc->sc_vhid; - } + if (sc->sc_carpdev->if_type == IFT_ISO88025) { + sc->sc_carplladdr[0] = 3; + sc->sc_carplladdr[1] = 0; + sc->sc_carplladdr[2] = 0x40 >> (sc->sc_vhid - 1); + sc->sc_carplladdr[3] = 0x40000 >> (sc->sc_vhid - 1); + sc->sc_carplladdr[4] = 0; + sc->sc_carplladdr[5] = 0; + } else { + if (sc->sc_if.if_flags & IFF_LINK2) + sc->sc_carplladdr[0] = 1; + else + sc->sc_carplladdr[0] = 0; + sc->sc_carplladdr[1] = 0; + sc->sc_carplladdr[2] = 0x5e; + sc->sc_carplladdr[3] = 0; + sc->sc_carplladdr[4] = 1; + sc->sc_carplladdr[5] = sc->sc_vhid; + } + } else + bzero(&sc->sc_carplladdr, ETHER_ADDR_LEN); - /* Make sure the enaddr has changed before further twiddling. */ - if (bcmp(&sc->sc_ac.ac_enaddr, LLADDR(sc->sc_if.if_sadl), - sc->sc_if.if_addrlen) != 0) { - bcopy(&sc->sc_ac.ac_enaddr, - LLADDR(sc->sc_if.if_sadl), sc->sc_if.if_addrlen); + /* + * Use the carp lladdr if the running one isn't manually set. + * Only compare static parts of the lladdr. + */ + if ((bcmp(sc->sc_ac.ac_enaddr + 1, sc->sc_carplladdr + 1, + ETHER_ADDR_LEN - 2) == 0) || + (!sc->sc_ac.ac_enaddr[0] && !sc->sc_ac.ac_enaddr[1] && + !sc->sc_ac.ac_enaddr[2] && !sc->sc_ac.ac_enaddr[3] && + !sc->sc_ac.ac_enaddr[4] && !sc->sc_ac.ac_enaddr[5])) + bcopy(sc->sc_carplladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); + /* Make sure the enaddr has changed before further twiddling. */ + if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN) != 0) { + bcopy(sc->sc_ac.ac_enaddr, LLADDR(sc->sc_if.if_sadl), + ETHER_ADDR_LEN); + bcopy(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN); #ifdef INET6 /* * (re)attach a link-local address which matches @@ -1659,6 +1814,8 @@ carp_set_enaddr(struct carp_softc *sc) */ in6_ifattach_linklocal(&sc->sc_if, NULL); #endif + carp_set_state(sc, INIT); + carp_setrun(sc, 0); } } @@ -1933,7 +2090,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) #endif /* INET */ #ifdef INET6 case AF_INET6: - sc->sc_if.if_flags|= IFF_UP; + sc->sc_if.if_flags |= IFF_UP; error = carp_set_addr6(sc, satosin6(ifa->ifa_addr)); break; #endif /* INET6 */ @@ -1961,6 +2118,9 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) sc->sc_if.if_flags |= IFF_UP; carp_setrun(sc, 0); } + carp_set_enaddr(sc); /* for changes on LINK2 */ + if (ifr->ifr_flags & IFF_LINK0) + carp_update_lsmask(sc); break; case SIOCSVH: @@ -1989,7 +2149,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) break; } } - if (carpr.carpr_vhid > 0) { + if (carpr.carpr_vhid > 0 && carpr.carpr_vhid != sc->sc_vhid) { if (carpr.carpr_vhid > 255) { error = EINVAL; break; @@ -2002,9 +2162,11 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) vr->sc_vhid == carpr.carpr_vhid) return (EINVAL); } - sc->sc_vhid = carpr.carpr_vhid; - carp_set_enaddr(sc); - carp_set_state(sc, INIT); + if (carpr.carpr_vhid != sc->sc_vhid) { + sc->sc_vhid = carpr.carpr_vhid; + carp_set_enaddr(sc); + carp_set_state(sc, INIT); + } error--; } if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) { @@ -2060,6 +2222,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) error = EINVAL; } + if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN) != 0) + carp_set_enaddr(sc); carp_hmac_prepare(sc); return (error); } @@ -2114,6 +2278,8 @@ carp_set_state(struct carp_softc *sc, int state) return; sc->sc_state = state; + carp_update_lsmask(sc); + switch (state) { case BACKUP: sc->sc_if.if_link_state = LINK_STATE_DOWN; diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h index a2d966736bf..874b96abed9 100644 --- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.h,v 1.21 2006/06/02 19:53:12 mpf Exp $ */ +/* $OpenBSD: ip_carp.h,v 1.22 2007/03/18 23:23:17 mpf Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -159,11 +159,12 @@ void carp_group_demote_adj(struct ifnet *, int); int carp6_proto_input(struct mbuf **, int *, int); int carp_iamatch(struct in_ifaddr *, u_char *, u_int32_t *, u_int32_t); -struct ifaddr *carp_iamatch6(void *, struct in6_addr *); +int carp_iamatch6(struct ifnet *, struct ifaddr *); struct ifnet *carp_ourether(void *, struct ether_header *, u_char, int); int carp_input(struct mbuf *, u_int8_t *, u_int8_t *, u_int16_t); int carp_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); int carp_sysctl(int *, u_int, void *, size_t *, void *, size_t); +int carp_lsdrop(struct mbuf *, sa_family_t, u_int32_t *, u_int32_t *); #endif /* _KERNEL */ #endif /* _NETINET_IP_CARP_H_ */ diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 08861700058..ad48e0ca815 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_icmp.c,v 1.72 2007/01/03 18:39:56 claudio Exp $ */ +/* $OpenBSD: ip_icmp.c,v 1.73 2007/03/18 23:23:17 mpf Exp $ */ /* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */ /* @@ -68,6 +68,8 @@ * Research Laboratory (NRL). */ +#include "carp.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> @@ -86,6 +88,11 @@ #include <netinet/ip_var.h> #include <netinet/icmp_var.h> +#if NCARP > 0 +#include <net/if_types.h> +#include <netinet/ip_carp.h> +#endif + /* * ICMP routines: error generation, receive packet processing, and * routines to turnaround packets back to the originator, and @@ -450,6 +457,13 @@ icmp_input(struct mbuf *m, ...) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); #endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + carp_lsdrop(m, AF_INET, &icmpsrc.sin_addr.s_addr, + &ip->ip_dst.s_addr)) + goto freeit; +#endif /* * XXX if the packet contains [IPv4 AH TCP], we can't make a * notification to TCP layer. @@ -521,6 +535,13 @@ icmp_input(struct mbuf *m, ...) ip->ip_src = ia->ia_dstaddr.sin_addr; } reflect: +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, + &ip->ip_dst.s_addr)) + goto freeit; +#endif /* Free packet atttributes */ if (m->m_flags & M_PKTHDR) m_tag_delete_chain(m); @@ -563,6 +584,13 @@ reflect: } #endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + carp_lsdrop(m, AF_INET, &icmpsrc.sin_addr.s_addr, + &ip->ip_dst.s_addr)) + goto freeit; +#endif rt = NULL; rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst), (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index deca652ad8a..af1a440c73a 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.146 2006/12/28 20:06:10 deraadt Exp $ */ +/* $OpenBSD: ip_input.c,v 1.147 2007/03/18 23:23:17 mpf Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -33,6 +33,7 @@ */ #include "pf.h" +#include "carp.h" #include <sys/param.h> #include <sys/systm.h> @@ -65,6 +66,11 @@ #include <netinet/ip_ipsp.h> #endif /* IPSEC */ +#if NCARP > 0 +#include <net/if_types.h> +#include <netinet/ip_carp.h> +#endif + #define IPMTUDISCTIMEOUT (10 * 60) /* as per RFC 1191 */ struct ipqhead ipq; @@ -370,6 +376,15 @@ ipv4_input(m) m_adj(m, len - m->m_pkthdr.len); } +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + ip->ip_p != IPPROTO_ICMP && + carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, + &ip->ip_dst.s_addr)) + goto bad; +#endif + #if NPF > 0 /* * Packet filter @@ -462,6 +477,14 @@ ipv4_input(m) ip->ip_dst.s_addr == INADDR_ANY) goto ours; +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + ip->ip_p == IPPROTO_ICMP && + carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, + &ip->ip_dst.s_addr)) + goto bad; +#endif /* * Not for us; forward if possible and desirable. */ diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index e16442596cb..aaa3c57f5f1 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: icmp6.c,v 1.92 2007/01/16 11:05:25 itojun Exp $ */ +/* $OpenBSD: icmp6.c,v 1.93 2007/03/18 23:23:17 mpf Exp $ */ /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ /* @@ -61,6 +61,9 @@ * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 */ +#include "faith.h" +#include "carp.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -91,7 +94,9 @@ #include <netinet6/in6_ifattach.h> #include <netinet6/ip6protosw.h> -#include "faith.h" +#if NCARP > 0 +#include <netinet/ip_carp.h> +#endif /* inpcb members */ #define in6pcb inpcb @@ -474,6 +479,14 @@ icmp6_input(mp, offp, proto) } #endif +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + icmp6->icmp6_type == ICMP6_ECHO_REQUEST && + carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32, + ip6->ip6_dst.s6_addr32)) + goto freeit; +#endif icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; switch (icmp6->icmp6_type) { diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 71b6c4f43b3..030d2bdbfea 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.74 2006/12/28 20:08:15 deraadt Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.75 2007/03/18 23:23:17 mpf Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -62,6 +62,7 @@ */ #include "pf.h" +#include "carp.h" #include <sys/param.h> #include <sys/systm.h> @@ -109,6 +110,11 @@ #include <net/pfvar.h> #endif +#if NCARP > 0 +#include <netinet/in_var.h> +#include <netinet/ip_carp.h> +#endif + extern struct domain inet6domain; extern struct ip6protosw inet6sw[]; @@ -246,6 +252,14 @@ ip6_input(m) goto bad; } +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + ip6->ip6_nxt != IPPROTO_ICMPV6 && + carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32, + ip6->ip6_dst.s6_addr32)) + goto bad; +#endif ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; /* @@ -523,6 +537,14 @@ ip6_input(m) } #endif +#if NCARP > 0 + if (m->m_pkthdr.rcvif->if_type == IFT_CARP && + m->m_pkthdr.rcvif->if_flags & IFF_LINK0 && + ip6->ip6_nxt == IPPROTO_ICMPV6 && + carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32, + ip6->ip6_dst.s6_addr32)) + goto bad; +#endif /* * Now there is no reason to process the packet if it's not our own * and we're not a router. diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index e3a1fe72926..a5f425eef0b 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6_nbr.c,v 1.42 2006/11/17 01:11:23 itojun Exp $ */ +/* $OpenBSD: nd6_nbr.c,v 1.43 2007/03/18 23:23:17 mpf Exp $ */ /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ /* @@ -193,10 +193,13 @@ nd6_ns_input(m, off, icmp6len) */ /* (1) and (3) check. */ #if NCARP > 0 - if (ifp->if_carp && ifp->if_type != IFT_CARP) - ifa = carp_iamatch6(ifp->if_carp, &taddr6); - if (!ifa) + if (ifp->if_type == IFT_CARP) { ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); + if (ifa && !carp_iamatch6(ifp, ifa)) + ifa = NULL; + } else { + ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); + } #else ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); #endif |