summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarco Pfatschbacher <mpf@cvs.openbsd.org>2008-02-05 22:57:32 +0000
committerMarco Pfatschbacher <mpf@cvs.openbsd.org>2008-02-05 22:57:32 +0000
commit279d8911f3838a3d1546b31c4801fac650ddc9ce (patch)
tree3f4efb4bfc2385425ae2ad31c7f392ddc1729137 /sys
parent1c85bd544fb9501c3922670c79d44a2d5baedad0 (diff)
Move carp load balancing (ARP/IP) to a simpler configuration scheme.
Instead of using the same IP on multiple interfaces, carp has to be configured with the new "carpnodes" and "balancing" options. # ifconfig carp0 carpnodes 1:0,2:100,3:100 balancing ip carpdev sis0 192.168.5.50 Please note, that this is a flag day for anyone using carp balancing. You'll need to adjust your configuration accordingly. Addititionally this diff adds IPv6 NDP balancing support. Tested and OK mcbride@, reyk@. Manpage help by jmc@.
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if_ethersubr.c8
-rw-r--r--sys/netinet/if_ether.c22
-rw-r--r--sys/netinet/ip_carp.c378
-rw-r--r--sys/netinet/ip_carp.h23
-rw-r--r--sys/netinet/ip_icmp.c5
-rw-r--r--sys/netinet/ip_input.c14
-rw-r--r--sys/netinet6/icmp6.c3
-rw-r--r--sys/netinet6/ip6_input.c4
-rw-r--r--sys/netinet6/nd6_nbr.c4
9 files changed, 196 insertions, 265 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 7ea08f926be..26e2b69bd29 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.113 2008/01/17 17:50:59 bluhm Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.114 2008/02/05 22:57:30 mpf Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -564,12 +564,10 @@ ether_input(ifp, eh, m)
(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 */
+ /* clear mcast if received on a carp IP balanced 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))
+ carp_our_mcastaddr(ifp, (u_int8_t *)&eh->ether_dhost))
m->m_flags &= ~(M_BCAST|M_MCAST);
}
#endif /* NCARP > 0 */
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index fa9e562331e..4704fed67cc 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ether.c,v 1.69 2007/11/06 21:52:00 miod Exp $ */
+/* $OpenBSD: if_ether.c,v 1.70 2008/02/05 22:57:30 mpf Exp $ */
/* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
/*
@@ -531,13 +531,13 @@ in_arpinput(m)
#if NBRIDGE > 0
struct in_ifaddr *bridge_ia = NULL;
#endif
-#if NCARP > 0
- u_int32_t count = 0, index = 0;
-#endif
struct sockaddr_dl *sdl;
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
u_int8_t *enaddr = NULL;
+#if NCARP > 0
+ u_int8_t *ether_shost = NULL;
+#endif
int op;
ea = mtod(m, struct ether_arp *);
@@ -563,10 +563,10 @@ in_arpinput(m)
if (ia->ia_ifp->if_type == IFT_CARP &&
((ia->ia_ifp->if_flags & (IFF_UP|IFF_RUNNING)) ==
(IFF_UP|IFF_RUNNING))) {
- index++;
if (ia->ia_ifp == m->m_pkthdr.rcvif &&
+ (op == ARPOP_REPLY ||
carp_iamatch(ia, ea->arp_sha,
- &count, index))
+ &enaddr, &ether_shost)))
break;
} else
#endif
@@ -589,7 +589,7 @@ in_arpinput(m)
m->m_pkthdr.rcvif->if_bridge ==
ia->ia_ifp->if_carpdev->if_bridge &&
carp_iamatch(ia, ea->arp_sha,
- &count, index))
+ &enaddr, &ether_shost))
bridge_ia = ia;
#endif
}
@@ -731,12 +731,10 @@ reply:
eh = (struct ether_header *)sa.sa_data;
bcopy(ea->arp_tha, eh->ether_dhost, sizeof(eh->ether_dhost));
#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
+ if (ether_shost)
+ enaddr = ether_shost;
#endif
- bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost));
+ bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost));
eh->ether_type = htons(ETHERTYPE_ARP);
sa.sa_family = pseudo_AF_HDRCMPLT;
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 597809f0e5b..82f9ba870e7 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.c,v 1.160 2008/01/02 03:33:18 brad Exp $ */
+/* $OpenBSD: ip_carp.c,v 1.161 2008/02/05 22:57:30 mpf Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -107,7 +107,7 @@ enum { HMAC_ORIG=0, HMAC_NOV6LL=1, HMAC_MAX=2 };
struct carp_vhost_entry {
LIST_ENTRY(carp_vhost_entry) vhost_entries;
struct carp_softc *parent_sc;
- int master;
+ int vhe_leader;
int vhid;
int advskew;
enum { INIT = 0, BACKUP, MASTER } state;
@@ -123,6 +123,7 @@ struct carp_vhost_entry {
SHA1_CTX vhe_sha1[HMAC_MAX];
u_int8_t vhe_enaddr[ETHER_ADDR_LEN];
+ struct sockaddr_dl vhe_sdl; /* for IPv6 ndp balancing */
};
struct carp_softc {
@@ -151,6 +152,7 @@ struct carp_softc {
int sc_vhe_count;
u_int8_t sc_vhids[CARP_MAXNODES];
u_int8_t sc_advskews[CARP_MAXNODES];
+ u_int8_t sc_balancing;
int sc_naddrs;
int sc_naddrs6;
@@ -162,14 +164,13 @@ struct carp_softc {
u_int32_t sc_hashkey[2];
u_int32_t sc_lsmask; /* load sharing mask */
int sc_lscount; /* # load sharing interfaces (max 32) */
-
int sc_delayed_arp; /* delayed ARP request countdown */
LIST_HEAD(__carp_mchead, carp_mc_entry) carp_mc_listhead;
struct carp_vhost_entry *cur_vhe; /* current active vhe */
};
-int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0, 0 }; /* XXX for now */
+int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0 }; /* XXX for now */
struct carpstats carpstats;
struct carp_if {
@@ -208,7 +209,7 @@ void carp_send_ad(void *);
void carp_send_arp(struct carp_softc *);
void carp_master_down(void *);
int carp_ioctl(struct ifnet *, u_long, caddr_t);
-int carp_vhids_ioctl(struct carp_softc *, struct carpreq);
+int carp_vhids_ioctl(struct carp_softc *, struct carpreq *);
int carp_check_dup_vhids(struct carp_softc *, struct carp_if *,
struct carpreq *);
void carp_ifgroup_ioctl(struct ifnet *, u_long, caddr_t);
@@ -218,8 +219,6 @@ void carp_setrun_all(struct carp_softc *, sa_family_t);
void carp_setrun(struct carp_vhost_entry *, sa_family_t);
void carp_set_state_all(struct carp_softc *, int);
void carp_set_state(struct carp_vhost_entry *, int);
-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 *);
@@ -291,7 +290,7 @@ carp_hmac_prepare_ctx(struct carp_vhost_entry *vhe, u_int8_t ctx)
SHA1Update(&vhe->vhe_sha1[ctx], (void *)&type, sizeof(type));
/* generate a key for the arpbalance hash, before the vhid is hashed */
- if (vhe->master) {
+ if (vhe->vhe_leader) {
bcopy(&vhe->vhe_sha1[ctx], &sha1ctx, sizeof(sha1ctx));
SHA1Final((unsigned char *)kmd, &sha1ctx);
sc->sc_hashkey[0] = kmd[0] ^ kmd[1];
@@ -299,7 +298,7 @@ carp_hmac_prepare_ctx(struct carp_vhost_entry *vhe, u_int8_t ctx)
}
/* the rest of the precomputation */
- if (vhe->master && bcmp(sc->sc_ac.ac_enaddr, vhe->vhe_enaddr,
+ if (vhe->vhe_leader && bcmp(sc->sc_ac.ac_enaddr, vhe->vhe_enaddr,
ETHER_ADDR_LEN) != 0)
SHA1Update(&vhe->vhe_sha1[ctx], sc->sc_ac.ac_enaddr,
ETHER_ADDR_LEN);
@@ -404,7 +403,7 @@ carp_setroute(struct carp_softc *sc, int cmd)
TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
switch (ifa->ifa_addr->sa_family) {
case AF_INET: {
- int count = 0, error;
+ int error;
struct sockaddr sa;
struct rtentry *rt;
struct radix_node_head *rnh;
@@ -414,21 +413,6 @@ carp_setroute(struct carp_softc *sc, int cmd)
struct sockaddr_rtlabel sa_rl;
const char *label;
- /*
- * Avoid screwing with the routes if there are other
- * carp interfaces which are master and have the same
- * address.
- */
- if (sc->sc_carpdev != NULL &&
- sc->sc_carpdev->if_carp != NULL) {
- count = carp_addrcount(
- (struct carp_if *)sc->sc_carpdev->if_carp,
- ifa, CARP_COUNT_MASTER);
- if ((cmd == RTM_ADD && count != 1) ||
- (cmd == RTM_DELETE && count != 0))
- continue;
- }
-
/* Remove the existing host route, if any */
bzero(&info, sizeof(info));
info.rti_info[RTAX_DST] = ifa->ifa_addr;
@@ -515,6 +499,8 @@ carp_setroute(struct carp_softc *sc, int cmd)
#ifdef INET6
case AF_INET6:
+ if (sc->sc_balancing >= CARP_BAL_IP)
+ continue;
if (cmd == RTM_ADD)
in6_ifaddloop(ifa);
else
@@ -748,7 +734,7 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
timeout_del(&vhe->ad_tmo);
carp_set_state(vhe, BACKUP);
carp_setrun(vhe, 0);
- if (vhe->master)
+ if (vhe->vhe_leader)
carp_setroute(sc, RTM_DELETE);
}
break;
@@ -903,9 +889,9 @@ carp_new_vhost(struct carp_softc *sc, int vhid, int advskew)
timeout_set(&vhe->md_tmo, carp_master_down, vhe);
timeout_set(&vhe->md6_tmo, carp_master_down, vhe);
- /* mark the first vhe as master */
+ /* mark the first vhe as leader */
if (LIST_EMPTY(&sc->carp_vhosts)) {
- vhe->master = 1;
+ vhe->vhe_leader = 1;
LIST_INSERT_HEAD(&sc->carp_vhosts, vhe, vhost_entries);
sc->sc_vhe_count = 1;
return (0);
@@ -1187,7 +1173,7 @@ carp_send_ad(void *v)
} else
sc->sc_sendad_errors = 0;
}
- if (vhe->master) {
+ if (vhe->vhe_leader) {
if (sc->sc_delayed_arp > 0)
sc->sc_delayed_arp--;
if (sc->sc_delayed_arp == 0) {
@@ -1298,10 +1284,6 @@ 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 */
@@ -1368,153 +1350,36 @@ carp_hash(struct carp_softc *sc, u_char *src)
return (c);
}
-int
-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) {
- 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 (LIST_FIRST(&vh->carp_vhosts)->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 carp_vhost_entry *vhe;
- struct ifaddr *ifa, *ifa0 = NULL;
- int cur, last, count, found;
-
- if (!sc->sc_carpdev)
- return;
- cif = (struct carp_if *)sc->sc_carpdev->if_carp;
+ int count;
- /*
- * 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)
+ if (!sc->sc_balancing)
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;
+ sc->sc_lsmask = 0;
count = 0;
- do {
- found = 0;
- last = cur;
- cur = 255;
- TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
- vhe = LIST_FIRST(&vh->carp_vhosts);
- 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 &&
- ifa0->ifa_addr->sa_family == AF_INET &&
- ifatoia(ifa0)->ia_addr.sin_addr.s_addr ==
- ifatoia(ifa)->ia_addr.sin_addr.s_addr)
- 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 && vhe->vhid > last && vhe->vhid < cur) {
- cur = vhe->vhid;
- curvh = vh;
- found++;
- }
- }
- if (found) {
- if (LIST_FIRST(&curvh->carp_vhosts)->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))
+ LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+ if (vhe->state == MASTER && count < sizeof(sc->sc_lsmask) * 8)
+ sc->sc_lsmask |= 1 << count;
+ count++;
+ }
+ sc->sc_lscount = count;
+ CARP_LOG(sc, ("carp_update_lsmask: %x", sc->sc_lsmask));
}
int
-carp_iamatch(struct in_ifaddr *ia, u_char *src,
- u_int32_t *count, u_int32_t index)
+carp_iamatch(struct in_ifaddr *ia, u_char *src, u_int8_t **sha,
+ u_int8_t **ether_shost)
{
struct carp_softc *sc = ia->ia_ifp->if_softc;
struct carp_vhost_entry *vhe = LIST_FIRST(&sc->carp_vhosts);
- /*
- * 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]) {
+ if (sc->sc_balancing == CARP_BAL_ARP) {
+ int lshash;
/*
* We use the source MAC address to decide which virtual host
* should handle the request. If we're master of that virtual
@@ -1522,18 +1387,25 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src,
* on the floor.
*/
- /* Count the eligible carp interfaces with this address */
- if (*count == 0)
- *count = carp_addrcount(
- (struct carp_if *)ia->ia_ifp->if_carpdev->if_carp,
- (struct ifaddr *)ia, CARP_COUNT_RUNNING);
-
- /* This should never happen, but... */
- if (*count == 0)
+ if (sc->sc_lscount == 0) /* just to be safe */
return (0);
-
- if (carp_hash(sc, src) % *count == index - 1 &&
- LIST_FIRST(&sc->carp_vhosts)->state == MASTER) {
+ lshash = carp_hash(sc, src) % sc->sc_lscount;
+ if ((1 << lshash) & sc->sc_lsmask) {
+ int i = 0;
+ LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+ if (i++ == lshash)
+ break;
+ }
+ if (vhe == NULL)
+ return (0);
+ *sha = vhe->vhe_enaddr;
+ return (1);
+ }
+ } else if (sc->sc_balancing == CARP_BAL_IPSTEALTH ||
+ sc->sc_balancing == CARP_BAL_IP) {
+ if (vhe->state == MASTER) {
+ *ether_shost = ((struct arpcom *)sc->sc_carpdev)->
+ ac_enaddr;
return (1);
}
} else {
@@ -1546,21 +1418,41 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src,
#ifdef INET6
int
-carp_iamatch6(struct ifnet *ifp, struct ifaddr *ifa)
+carp_iamatch6(struct ifnet *ifp, u_char *src, struct sockaddr_dl **sdl)
{
struct carp_softc *sc = ifp->if_softc;
+ struct carp_vhost_entry *vhe = LIST_FIRST(&sc->carp_vhosts);
- /*
- * 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);
+ if (sc->sc_balancing == CARP_BAL_ARP) {
+ int lshash;
+ /*
+ * We use the source MAC address to decide which virtual host
+ * should handle the request. If we're master of that virtual
+ * host, then we respond, otherwise, just drop the ndp packet
+ * on the floor.
+ */
- if (LIST_FIRST(&sc->carp_vhosts)->state == MASTER)
- return (1);
+ /* can happen if optional src lladdr is not provided */
+ if (src == NULL)
+ return (0);
+ if (sc->sc_lscount == 0) /* just to be safe */
+ return (0);
+ lshash = carp_hash(sc, src) % sc->sc_lscount;
+ if ((1 << lshash) & sc->sc_lsmask) {
+ int i = 0;
+ LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) {
+ if (i++ == lshash)
+ break;
+ }
+ if (vhe == NULL)
+ return (0);
+ *sdl = &vhe->vhe_sdl;
+ return (1);
+ }
+ } else {
+ if (vhe->state == MASTER)
+ return (1);
+ }
return (0);
}
@@ -1579,14 +1471,22 @@ carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src)
ena = (u_int8_t *)&eh->ether_dhost;
TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
- /* XXX need to check all vhes */
- struct carp_vhost_entry *vhe = LIST_FIRST(&vh->carp_vhosts);
+ struct carp_vhost_entry *vhe;
if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
(IFF_UP|IFF_RUNNING))
continue;
- if ((vhe->state == MASTER || vh->sc_if.if_flags & IFF_LINK0)
- && !bcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
- return (&vh->sc_if);
+ if (vh->sc_balancing == CARP_BAL_ARP) {
+ LIST_FOREACH(vhe, &vh->carp_vhosts, vhost_entries)
+ if (vhe->state == MASTER &&
+ !bcmp(ena, vhe->vhe_enaddr, ETHER_ADDR_LEN))
+ return (&vh->sc_if);
+ } else {
+ vhe = LIST_FIRST(&vh->carp_vhosts);
+ if ((vhe->state == MASTER ||
+ vh->sc_balancing >= CARP_BAL_IP) &&
+ !bcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
+ return (&vh->sc_if);
+ }
}
return (NULL);
}
@@ -1596,8 +1496,9 @@ carp_rewrite_lladdr(struct ifnet *ifp, u_int8_t *s_enaddr)
{
struct carp_softc *sc = ifp->if_softc;
- if (!(ifp->if_flags & IFF_LINK1) && sc->cur_vhe) {
- if (sc->cur_vhe->master)
+ if (sc->sc_balancing != CARP_BAL_IPSTEALTH &&
+ sc->sc_balancing != CARP_BAL_IP && sc->cur_vhe) {
+ if (sc->cur_vhe->vhe_leader)
bcopy((caddr_t)sc->sc_ac.ac_enaddr,
(caddr_t)s_enaddr, ETHER_ADDR_LEN);
else
@@ -1607,6 +1508,18 @@ carp_rewrite_lladdr(struct ifnet *ifp, u_int8_t *s_enaddr)
}
int
+carp_our_mcastaddr(struct ifnet *ifp, u_int8_t *d_enaddr)
+{
+ struct carp_softc *sc = ifp->if_softc;
+
+ if (sc->sc_balancing != CARP_BAL_IP)
+ return (0);
+
+ return(!bcmp(sc->sc_ac.ac_enaddr, d_enaddr, ETHER_ADDR_LEN));
+}
+
+
+int
carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype)
{
struct ether_header eh;
@@ -1660,6 +1573,8 @@ carp_lsdrop(struct mbuf *m, sa_family_t af, u_int32_t *src, u_int32_t *dst)
int match;
u_int32_t fold;
+ if (sc->sc_balancing < CARP_BAL_IP)
+ return (0);
/*
* Never drop carp advertisements.
* XXX Bad idea to pass all broadcast / multicast traffic?
@@ -1698,7 +1613,7 @@ carp_master_down(void *v)
case BACKUP:
carp_set_state(vhe, MASTER);
carp_send_ad(vhe);
- if (vhe->master) {
+ if (sc->sc_balancing == CARP_BAL_NONE && vhe->vhe_leader) {
carp_send_arp(sc);
/* Schedule a delayed ARP to deal w/ some L3 switches */
sc->sc_delayed_arp = 2;
@@ -1707,7 +1622,7 @@ carp_master_down(void *v)
#endif /* INET6 */
}
carp_setrun(vhe, 0);
- if (vhe->master)
+ if (vhe->vhe_leader)
carp_setroute(sc, RTM_ADD);
carpstats.carps_preempt++;
break;
@@ -1744,7 +1659,7 @@ carp_setrun(struct carp_vhost_entry *vhe, sa_family_t af)
sc->sc_if.if_flags |= IFF_RUNNING;
} else {
sc->sc_if.if_flags &= ~IFF_RUNNING;
- if (vhe->master)
+ if (vhe->vhe_leader)
carp_setroute(sc, RTM_DELETE);
return;
}
@@ -1752,7 +1667,7 @@ carp_setrun(struct carp_vhost_entry *vhe, sa_family_t af)
switch (vhe->state) {
case INIT:
carp_set_state(vhe, BACKUP);
- if (vhe->master)
+ if (vhe->vhe_leader)
carp_setroute(sc, RTM_DELETE);
carp_setrun(vhe, 0);
break;
@@ -1760,7 +1675,7 @@ carp_setrun(struct carp_vhost_entry *vhe, sa_family_t af)
timeout_del(&vhe->ad_tmo);
tv.tv_sec = 3 * sc->sc_advbase;
tv.tv_usec = vhe->advskew * 1000000 / 256;
- if (vhe->master)
+ if (vhe->vhe_leader)
sc->sc_delayed_arp = -1;
switch (af) {
#ifdef INET
@@ -1924,7 +1839,7 @@ carp_set_vhe_enaddr(struct carp_vhost_entry *vhe)
struct carp_softc *sc = vhe->parent_sc;
if (vhe->vhid != 0 && sc->sc_carpdev) {
- if (vhe->master && sc->sc_if.if_flags & IFF_LINK2)
+ if (vhe->vhe_leader && sc->sc_balancing == CARP_BAL_IP)
vhe->vhe_enaddr[0] = 1;
else
vhe->vhe_enaddr[0] = 0;
@@ -1933,6 +1848,10 @@ carp_set_vhe_enaddr(struct carp_vhost_entry *vhe)
vhe->vhe_enaddr[3] = 0;
vhe->vhe_enaddr[4] = 1;
vhe->vhe_enaddr[5] = vhe->vhid;
+
+ vhe->vhe_sdl.sdl_family = AF_LINK;
+ vhe->vhe_sdl.sdl_alen = ETHER_ADDR_LEN;
+ bcopy(vhe->vhe_enaddr, vhe->vhe_sdl.sdl_data, ETHER_ADDR_LEN);
} else
bzero(vhe->vhe_enaddr, ETHER_ADDR_LEN);
}
@@ -2284,9 +2203,6 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
sc->sc_if.if_flags |= IFF_UP;
carp_setrun_all(sc, 0);
}
- carp_set_enaddr(sc); /* for changes on LINK2 */
- if (ifr->ifr_flags & IFF_LINK0)
- carp_update_lsmask(sc);
break;
case SIOCSVH:
@@ -2318,7 +2234,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
break;
}
}
- if ((error = carp_vhids_ioctl(sc, carpr)))
+ if ((error = carp_vhids_ioctl(sc, &carpr)))
return (error);
if (carpr.carpr_advbase > 0) {
if (carpr.carpr_advbase > 255) {
@@ -2336,6 +2252,15 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
bcopy(carpr.carpr_advskews, sc->sc_advskews,
sizeof(sc->sc_advskews));
}
+ if (sc->sc_balancing != carpr.carpr_balancing) {
+ if (carpr.carpr_balancing > CARP_BAL_MAXID) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_balancing = carpr.carpr_balancing;
+ carp_set_enaddr(sc);
+ carp_update_lsmask(sc);
+ }
bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key));
if (error > 0)
error = EINVAL;
@@ -2358,6 +2283,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
i++;
}
carpr.carpr_advbase = sc->sc_advbase;
+ carpr.carpr_balancing = sc->sc_balancing;
if (suser(p, p->p_acflag) == 0)
bcopy(sc->sc_key, carpr.carpr_key,
sizeof(carpr.carpr_key));
@@ -2417,42 +2343,53 @@ carp_check_dup_vhids(struct carp_softc *sc, struct carp_if *cif,
}
int
-carp_vhids_ioctl(struct carp_softc *sc, struct carpreq carpr)
+carp_vhids_ioctl(struct carp_softc *sc, struct carpreq *carpr)
{
- int i;
+ int i, j;
u_int8_t taken_vhids[256];
- if (carpr.carpr_vhids[0] == 0 ||
- !bcmp(sc->sc_vhids, carpr.carpr_vhids, sizeof(sc->sc_vhids)))
+ if (carpr->carpr_vhids[0] == 0 ||
+ !bcmp(sc->sc_vhids, carpr->carpr_vhids, sizeof(sc->sc_vhids)))
return (0);
bzero(taken_vhids, sizeof(taken_vhids));
- for (i = 0; carpr.carpr_vhids[i]; i++) {
- if (taken_vhids[carpr.carpr_vhids[i]])
+ for (i = 0; carpr->carpr_vhids[i]; i++) {
+ if (taken_vhids[carpr->carpr_vhids[i]])
return (EINVAL);
- taken_vhids[carpr.carpr_vhids[i]] = 1;
+ taken_vhids[carpr->carpr_vhids[i]] = 1;
if (sc->sc_carpdev) {
struct carp_if *cif;
cif = (struct carp_if *)sc->sc_carpdev->if_carp;
- if (carp_check_dup_vhids(sc, cif, &carpr))
+ if (carp_check_dup_vhids(sc, cif, carpr))
return (EINVAL);
}
- if (carpr.carpr_advskews[i] >= 255)
+ if (carpr->carpr_advskews[i] >= 255)
return (EINVAL);
}
+ /* set sane balancing defaults */
+ if (i <= 1)
+ carpr->carpr_balancing = CARP_BAL_NONE;
+ else if (carpr->carpr_balancing == CARP_BAL_NONE &&
+ sc->sc_balancing == CARP_BAL_NONE)
+ carpr->carpr_balancing = CARP_BAL_IP;
/* destroy all */
carp_del_all_timeouts(sc);
carp_destroy_vhosts(sc);
bzero(sc->sc_vhids, sizeof(sc->sc_vhids));
- for (i = 0; carpr.carpr_vhids[i]; i++) {
- if (carp_new_vhost(sc, carpr.carpr_vhids[i],
- carpr.carpr_advskews[i]))
- return (ENOMEM);
- sc->sc_vhids[i] = carpr.carpr_vhids[i];
- sc->sc_advskews[i] = carpr.carpr_advskews[i];
+ /* sort vhosts list by vhid */
+ for (j = 1; j <= 255; j++) {
+ for (i = 0; carpr->carpr_vhids[i]; i++) {
+ if (carpr->carpr_vhids[i] != j)
+ continue;
+ if (carp_new_vhost(sc, carpr->carpr_vhids[i],
+ carpr->carpr_advskews[i]))
+ return (ENOMEM);
+ sc->sc_vhids[i] = carpr->carpr_vhids[i];
+ sc->sc_advskews[i] = carpr->carpr_advskews[i];
+ }
}
carp_set_enaddr(sc);
carp_set_state_all(sc, INIT);
@@ -2508,7 +2445,8 @@ carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
vhe = sc->cur_vhe ? sc->cur_vhe : LIST_FIRST(&sc->carp_vhosts);
- if (sc->sc_carpdev != NULL && vhe->state == MASTER)
+ if (sc->sc_carpdev != NULL &&
+ (sc->sc_balancing || vhe->state == MASTER))
return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
else {
m_freem(m);
@@ -2537,7 +2475,7 @@ carp_set_state(struct carp_vhost_entry *vhe, int state)
carp_update_lsmask(sc);
/* only the master vhe creates link state messages */
- if (!vhe->master)
+ if (!vhe->vhe_leader)
return;
switch (state) {
diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h
index f2d9bf7b046..857d8563c2b 100644
--- a/sys/netinet/ip_carp.h
+++ b/sys/netinet/ip_carp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.h,v 1.25 2007/12/14 18:33:40 deraadt Exp $ */
+/* $OpenBSD: ip_carp.h,v 1.26 2008/02/05 22:57:31 mpf Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -132,6 +132,14 @@ struct carpreq {
u_int8_t carpr_vhids[CARP_MAXNODES];
u_int8_t carpr_advskews[CARP_MAXNODES];
u_int8_t carpr_states[CARP_MAXNODES];
+#define CARP_BAL_MODES "none", "arp", "ip", "ip-stealth", "ip-unicast"
+#define CARP_BAL_NONE 0
+#define CARP_BAL_ARP 1
+#define CARP_BAL_IP 2
+#define CARP_BAL_IPSTEALTH 3
+#define CARP_BAL_IPUNICAST 4
+#define CARP_BAL_MAXID 4
+ u_int8_t carpr_balancing;
int carpr_advbase;
unsigned char carpr_key[CARP_KEY_LEN];
};
@@ -142,16 +150,14 @@ struct carpreq {
#define CARPCTL_ALLOW 1 /* accept incoming CARP packets */
#define CARPCTL_PREEMPT 2 /* high-pri backup preemption mode */
#define CARPCTL_LOG 3 /* log bad packets */
-#define CARPCTL_ARPBALANCE 4 /* balance arp responses */
-#define CARPCTL_STATS 5 /* CARP stats */
-#define CARPCTL_MAXID 6
+#define CARPCTL_STATS 4 /* CARP stats */
+#define CARPCTL_MAXID 5
#define CARPCTL_NAMES { \
{ 0, 0 }, \
{ "allow", CTLTYPE_INT }, \
{ "preempt", CTLTYPE_INT }, \
{ "log", CTLTYPE_INT }, \
- { "arpbalance", CTLTYPE_INT }, \
{ "stats", CTLTYPE_STRUCT }, \
}
@@ -161,9 +167,9 @@ void carp_proto_input (struct mbuf *, ...);
void carp_carpdev_state(void *);
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);
-int carp_iamatch6(struct ifnet *, struct ifaddr *);
+int carp_iamatch(struct in_ifaddr *, u_char *, u_int8_t **,
+ u_int8_t **);
+int carp_iamatch6(struct ifnet *, u_char *, struct sockaddr_dl **);
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 *,
@@ -171,5 +177,6 @@ int carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
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 *);
void carp_rewrite_lladdr(struct ifnet *, u_int8_t *);
+int carp_our_mcastaddr(struct ifnet *, u_int8_t *);
#endif /* _KERNEL */
#endif /* _NETINET_IP_CARP_H_ */
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index bd727af3b58..664a14cd0a6 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_icmp.c,v 1.78 2007/12/13 20:00:53 reyk Exp $ */
+/* $OpenBSD: ip_icmp.c,v 1.79 2008/02/05 22:57:31 mpf Exp $ */
/* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */
/*
@@ -452,7 +452,6 @@ icmp_input(struct mbuf *m, ...)
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;
@@ -530,7 +529,6 @@ icmp_input(struct mbuf *m, ...)
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;
@@ -579,7 +577,6 @@ reflect:
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;
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index d8d3c01a4b4..2b691ffa1ec 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_input.c,v 1.156 2007/12/14 18:33:41 deraadt Exp $ */
+/* $OpenBSD: ip_input.c,v 1.157 2008/02/05 22:57:31 mpf Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
@@ -351,10 +351,8 @@ ipv4_input(m)
#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))
+ ip->ip_p != IPPROTO_ICMP && carp_lsdrop(m, AF_INET,
+ &ip->ip_src.s_addr, &ip->ip_dst.s_addr))
goto bad;
#endif
@@ -452,10 +450,8 @@ ipv4_input(m)
#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))
+ ip->ip_p == IPPROTO_ICMP && carp_lsdrop(m, AF_INET,
+ &ip->ip_src.s_addr, &ip->ip_dst.s_addr))
goto bad;
#endif
/*
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 4a0e360a936..8800a65f449 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: icmp6.c,v 1.94 2007/06/01 00:52:38 henning Exp $ */
+/* $OpenBSD: icmp6.c,v 1.95 2008/02/05 22:57:31 mpf Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@@ -481,7 +481,6 @@ icmp6_input(mp, offp, proto)
#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))
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 2459d5d2688..f101308eb9d 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_input.c,v 1.80 2007/12/14 18:33:41 deraadt Exp $ */
+/* $OpenBSD: ip6_input.c,v 1.81 2008/02/05 22:57:31 mpf Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@@ -258,7 +258,6 @@ ip6_input(m)
#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))
@@ -552,7 +551,6 @@ ip6_input(m)
#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))
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 6168ed52a84..aaa5ceccab4 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nd6_nbr.c,v 1.46 2007/12/09 21:24:58 hshoexer Exp $ */
+/* $OpenBSD: nd6_nbr.c,v 1.47 2008/02/05 22:57:31 mpf Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@@ -195,7 +195,7 @@ nd6_ns_input(m, off, icmp6len)
#if NCARP > 0
if (ifp->if_type == IFT_CARP) {
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
- if (ifa && !carp_iamatch6(ifp, ifa))
+ if (ifa && !carp_iamatch6(ifp, lladdr, &proxydl))
ifa = NULL;
} else {
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);