Unix Technical Forum

SEO

vBulletin Search Engine Optimization


Go Back   Unix Technical Forum > Unix Operating Systems > OpenBSD > mailing.openbsd.tech

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 02-18-2008, 07:28 AM
Ryan McBride
 
Posts: n/a
Default Re: CARP without address on the physical interface

Here is an updated version of the diff which fixes problems with 'make
build' and 'make release'.

- in ip_carp.h, define CARPDEVNAMSIZ instead of using IFNAMSIZ, so that
random applications don't have to include if.h
- get rid of carp_sendif(), store the pointer to carpdev directly in
struct ifnet, so random kernel code doesn't have to include ip_carp.h
- some files missing from the diff.
- other misc. cleanup.

As an aside, I've not recieved a single reports from a user about the
above problems, so I have to imagine that nobody cares enough to test
it! IF YOU USE CARP, YOU SHOULD TEST THIS CODE!

On Mon, Dec 06, 2004 at 02:10:10AM +0000, Ryan McBride wrote:
> Here's the long-promised diff which allows you to specify a physical
> interface 'carpdev' which the carp interface will bind to, and that
> interface does not have to have an IP address on the same subnet (or at
> all, in fact).
>
> $ sudo ifconfig carp3 192.168.10.10 vhid 10 carpdev hme0
>
> If you don't specify it, the attachment behaves as the current code, ie.
> it figures out the correct carpdev on the address. This means that
> existing configurations should work correctly with this diff.
>
> Pleas test this - it is important as it allows CARP to work on small
> subnets or other situations with address shortage. I'm interested in
> hearing reports of this code running on existing configurations as well
> as the new functionality that it provides.



Index: sys/net/if_ethersubr.c
================================================== =================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.81
diff -u -r1.81 if_ethersubr.c
--- sys/net/if_ethersubr.c 28 Nov 2004 23:39:45 -0000 1.81
+++ sys/net/if_ethersubr.c 6 Dec 2004 20:35:59 -0000
@@ -238,8 +238,8 @@
* Assumes that ifp is actually pointer to arpcom structure.
*/
int
-ether_output(ifp, m0, dst, rt0)
- struct ifnet *ifp;
+ether_output(ifp0, m0, dst, rt0)
+ struct ifnet *ifp0;
struct mbuf *m0;
struct sockaddr *dst;
struct rtentry *rt0;
@@ -251,8 +251,28 @@
struct rtentry *rt;
struct mbuf *mcopy = (struct mbuf *)0;
struct ether_header *eh;
- struct arpcom *ac = (struct arpcom *)ifp;
+ struct arpcom *ac = (struct arpcom *)ifp0;
short mflags;
+ struct ifnet *ifp = ifp0;
+
+#if NCARP > 0
+ if (ifp->if_type == IFT_CARP) {
+ struct ifaddr *ifa;
+
+ /* loop back if this is going to the carp interface */
+ if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP &&
+ (ifa = ifa_ifwithaddr(dst)) != NULL &&
+ ifa->ifa_ifp == ifp0)
+ return (looutput(ifp0, m, dst, rt0));
+
+ ifp = ifp->if_carpdev;
+ ac = (struct arpcom *)ifp;
+
+ if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) !=
+ (IFF_UP|IFF_RUNNING))
+ senderr(ENETDOWN);
+ }
+#endif /* NCARP > 0 */

if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
senderr(ENETDOWN);
@@ -513,12 +533,12 @@
#endif

#if NCARP > 0
- if (ifp->if_carp) {
- int error;
- error = carp_output(ifp, m, dst, NULL);
- if (error)
- goto bad;
- }
+ if (ifp->if_carp) {
+ int error;
+ error = carp_output(ifp0, m, dst, NULL);
+ if (error)
+ goto bad;
+ }
#endif

mflags = m->m_flags;
@@ -535,6 +555,10 @@
return (error);
}
ifp->if_obytes += len + ETHER_HDR_LEN;
+#if NCARP > 0
+ if (ifp != ifp0)
+ ifp0->if_obytes += len + ETHER_HDR_LEN;
+#endif /* NCARP > 0 */
if (mflags & M_MCAST)
ifp->if_omcasts++;
if ((ifp->if_flags & IFF_OACTIVE) == 0)
@@ -650,9 +674,9 @@
#endif /* NVLAN > 0 */

#if NCARP > 0
- if (ifp->if_carp &&
- carp_forus(ifp->if_carp, eh->ether_dhost))
- goto decapsulate;
+ if (ifp->if_carp && ifp->if_type != IFT_CARP &&
+ (carp_input(eh, m) == 0))
+ return;
#endif /* NCARP > 0 */

ac = (struct arpcom *)ifp;
Index: sys/netinet/if_ether.c
================================================== =================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.54
diff -u -r1.54 if_ether.c
--- sys/netinet/if_ether.c 21 Jun 2004 23:50:37 -0000 1.54
+++ sys/netinet/if_ether.c 6 Dec 2004 21:03:45 -0000
@@ -557,7 +557,7 @@
#endif

#if NCARP > 0
- if (ac->ac_if.if_carp) {
+ if (ac->ac_if.if_carp && ac->ac_if.if_type != IFT_CARP) {
if (carp_iamatch(ac->ac_if.if_carp, ia,
&isaddr, &enaddr))
break;
@@ -645,7 +645,11 @@
}
}
} else if (rt->rt_ifp != &ac->ac_if && !(ac->ac_if.if_bridge &&
- (rt->rt_ifp->if_bridge == ac->ac_if.if_bridge))) {
+ (rt->rt_ifp->if_bridge == ac->ac_if.if_bridge)) &&
+ !(rt->rt_ifp->if_type == IFT_CARP &&
+ rt->rt_ifp->if_carpdev == &ac->ac_if) &&
+ !(ac->ac_if.if_type == IFT_CARP &&
+ ac->ac_if.if_carpdev == rt->rt_ifp)) {
log(LOG_WARNING,
"arp: attempt to add entry for %s "
"on %s by %s on %s\n",
Index: sys/netinet/ip_carp.c
================================================== =================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.72
diff -u -r1.72 ip_carp.c
--- sys/netinet/ip_carp.c 30 Nov 2004 00:17:18 -0000 1.72
+++ sys/netinet/ip_carp.c 6 Dec 2004 23:17:38 -0000
@@ -29,7 +29,6 @@
/*
* TODO:
* - iface reconfigure
- * - track iface ip address changes;
* - support for hardware checksum calculations;
*
*/
@@ -41,6 +40,7 @@
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/socketvar.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/device.h>
@@ -92,10 +92,19 @@

#include <netinet/ip_carp.h>

+struct carp_mc_entry {
+ LIST_ENTRY(carp_mc_entry) mc_entries;
+ union {
+ struct ether_multi *mcu_enm;
+ } mc_u;
+ struct sockaddr_storage mc_addr;
+};
+#define mc_enm mc_u.mcu_enm
+
struct carp_softc {
struct arpcom sc_ac;
+#define sc_carpdev sc_ac.ac_if.if_carpdev
int if_flags; /* current flags to treat UP/DOWN */
- struct ifnet *sc_ifp;
struct in_ifaddr *sc_ia; /* primary iface address */
struct ip_moptions sc_imo;
#ifdef INET6
@@ -132,6 +141,7 @@
struct timeout sc_md_tmo; /* master down timeout */
struct timeout sc_md6_tmo; /* master down timeout */

+ LIST_HEAD(__carp_mchead, carp_mc_entry) carp_mc_listhead;
};

int carp_suppress_preempt = 0;
@@ -161,7 +171,7 @@
int carp_hmac_verify(struct carp_softc *, u_int32_t *,
unsigned char *);
void carp_setroute(struct carp_softc *, int);
-void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
+void carp_proto_input_c(struct mbuf *, struct carp_header *, sa_family_t);
void carpattach(int);
void carpdetach(struct carp_softc *);
int carp_prepare_ad(struct mbuf *, struct carp_softc *,
@@ -177,15 +187,20 @@
int carp_addrcount(struct carp_if *, struct in_ifaddr *, int);
enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING };

+void carp_multicast_cleanup(struct carp_softc *);
+int carp_set_ifp(struct carp_softc *, struct ifnet *);
int carp_set_addr(struct carp_softc *, struct sockaddr_in *);
-int carp_del_addr(struct carp_softc *, struct sockaddr_in *);
+int carp_join_multicast(struct carp_softc *, struct ifnet *);
#ifdef INET6
void carp_send_na(struct carp_softc *);
int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
-int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *);
+int carp_join_multicast6(struct carp_softc *, struct ifnet *);
#endif
int carp_clone_create(struct if_clone *, int);
int carp_clone_destroy(struct ifnet *);
+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 *);

struct if_clone carp_cloner =
IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy);
@@ -279,25 +294,91 @@
struct ifaddr *ifa;
int s;

- s = splnet();
+ s = splsoftnet();
TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
- if (ifa->ifa_addr->sa_family == AF_INET && sc->sc_ifp != NULL) {
- int count = carp_addrcount(
- (struct carp_if *)sc->sc_ifp->if_carp,
- ifatoia(ifa), CARP_COUNT_MASTER);
-
- if ((cmd == RTM_ADD && count == 1) ||
- (cmd == RTM_DELETE && count == 0))
- rtinit(ifa, cmd, RTF_UP | RTF_HOST);
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET: {
+ int count = 0;
+ struct sockaddr sa;
+ struct rtentry *rt;
+ struct radix_node_head *rnh =
+ rt_tables[ifa->ifa_addr->sa_family];
+ struct radix_node *rn;
+
+ /*
+ * 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,
+ ifatoia(ifa), CARP_COUNT_MASTER);
+ if ((cmd == RTM_ADD && count != 1) ||
+ (cmd == RTM_DELETE && count != 0))
+ continue;
+ }
+
+ /* Remove the existing host route, if any */
+ rtrequest(RTM_DELETE, ifa->ifa_addr,
+ ifa->ifa_addr, ifa->ifa_netmask,
+ RTF_HOST, NULL);
+
+ /* Check for a route on a physical interface */
+ rn = rnh->rnh_matchaddr(ifa->ifa_addr, rnh);
+ rt = (struct rtentry *)rn;
+
+ switch (cmd) {
+ case RTM_ADD:
+ if (rt && rt->rt_ifp != &sc->sc_ac.ac_if &&
+
+ rt->rt_flags & (RTF_CLONING|RTF_CLONED)) {
+ rtrequest(RTM_ADD, ifa->ifa_addr,
+ ifa->ifa_addr, ifa->ifa_netmask,
+ RTF_UP | RTF_HOST, NULL);
+ } else {
+ ifa->ifa_rtrequest = arp_rtrequest;
+ ifa->ifa_flags |= RTF_CLONING;
+
+ rtrequest(RTM_ADD, ifa->ifa_addr,
+ ifa->ifa_addr, ifa->ifa_netmask,
+ 0, NULL);
+ }
+ break;
+ case RTM_DELETE:
+ ifa->ifa_rtrequest = NULL;
+ ifa->ifa_flags &= ~RTF_CLONING;
+
+ if (!(rt && rt->rt_ifp != &sc->sc_ac.ac_if &&
+ rt->rt_flags & (RTF_CLONING|RTF_CLONED))) {
+ bcopy(ifa->ifa_addr, &sa, sizeof(sa));
+ satosin(&sa)->sin_addr.s_addr =
+ satosin(ifa->ifa_netmask
+ )->sin_addr.s_addr &
+ satosin(&sa)->sin_addr.s_addr;
+
+ rtrequest(cmd, &sa, ifa->ifa_addr,
+ ifa->ifa_netmask, 0, NULL);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
}
+
#ifdef INET6
- if (ifa->ifa_addr->sa_family == AF_INET6) {
+ case AF_INET6:
if (cmd == RTM_ADD)
in6_ifaddloop(ifa);
else
in6_ifremloop(ifa);
- }
+ break;
#endif /* INET6 */
+ default:
+ break;
+ }
}
splx(s);
}
@@ -308,7 +389,7 @@
* but it seems more efficient this way or not possible otherwise.
*/
void
-carp_input(struct mbuf *m, ...)
+carp_proto_input(struct mbuf *m, ...)
{
struct ip *ip = mtod(m, struct ip *);
struct carp_softc *sc = NULL;
@@ -328,7 +409,7 @@
}

/* check if received on a valid carp interface */
- if (m->m_pkthdr.rcvif->if_carp == NULL) {
+ if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
carpstats.carps_badif++;
CARP_LOG(sc, ("packet received on non-carp interface: %s",
m->m_pkthdr.rcvif->if_xname));
@@ -396,12 +477,12 @@
}
m->m_data -= iplen;

- carp_input_c(m, ch, AF_INET);
+ carp_proto_input_c(m, ch, AF_INET);
}

#ifdef INET6
int
-carp6_input(struct mbuf **mp, int *offp, int proto)
+carp6_proto_input(struct mbuf **mp, int *offp, int proto)
{
struct mbuf *m = *mp;
struct carp_softc *sc = NULL;
@@ -417,7 +498,7 @@
}

/* check if received on a valid carp interface */
- if (m->m_pkthdr.rcvif->if_carp == NULL) {
+ if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
carpstats.carps_badif++;
CARP_LOG(sc, ("packet received on non-carp interface: %s",
m->m_pkthdr.rcvif->if_xname));
@@ -456,23 +537,23 @@
}
m->m_data -= *offp;

- carp_input_c(m, ch, AF_INET6);
+ carp_proto_input_c(m, ch, AF_INET6);
return (IPPROTO_DONE);
}
#endif /* INET6 */

void
-carp_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)
{
struct carp_softc *sc;
- struct ifnet *ifp = m->m_pkthdr.rcvif;
u_int64_t tmp_counter;
struct timeval sc_tv, ch_tv;

- /* verify that the VHID is valid on the receiving interface */
- TAILQ_FOREACH(sc, &((struct carp_if *)ifp->if_carp)->vhif_vrs, sc_list)
+ TAILQ_FOREACH(sc, &((struct carp_if *)
+ m->m_pkthdr.rcvif->if_carpdev->if_carp)->vhif_vrs, sc_list)
if (sc->sc_vhid == ch->carp_vhid)
break;
+
if (!sc || (sc->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
(IFF_UP|IFF_RUNNING)) {
carpstats.carps_badvhid++;
@@ -484,25 +565,6 @@
sc->sc_ac.ac_if.if_ipackets++;
sc->sc_ac.ac_if.if_ibytes += m->m_pkthdr.len;

-#if NBPFILTER > 0
- if (sc->sc_ac.ac_if.if_bpf) {
- /*
- * We need to prepend the address family as
- * a four byte field. Cons up a dummy header
- * to pacify bpf. This is safe because bpf
- * will only read from the mbuf (i.e., it won't
- * try to free it or keep a pointer to it).
- */
- struct mbuf m0;
- u_int32_t af0 = htonl(af);
-
- m0.m_next = m;
- m0.m_len = sizeof(af0);
- m0.m_data = (char *)&af0;
- bpf_mtap(sc->sc_ac.ac_if.if_bpf, &m0);
- }
-#endif
-
/* verify the CARP version. */
if (ch->carp_version != CARP_VERSION) {
carpstats.carps_badver++;
@@ -642,22 +704,28 @@
timeout_set(&sc->sc_md_tmo, carp_master_down, sc);
timeout_set(&sc->sc_md6_tmo, carp_master_down, sc);

+ LIST_INIT(&sc->carp_mc_listhead);
ifp = &sc->sc_ac.ac_if;
ifp->if_softc = sc;
snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
unit);
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = 0;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = carp_ioctl;
- ifp->if_output = looutput;
+ ifp->if_output = ether_output;
ifp->if_start = carp_start;
ifp->if_type = IFT_CARP;
- ifp->if_snd.ifq_maxlen = ifqmaxlen;
- ifp->if_hdrlen = 0;
- if_attach(ifp);
+ ifp->if_addrlen = ETHER_ADDR_LEN;
+ ifp->if_hdrlen = ETHER_HDR_LEN;
+ ifp->if_mtu = ETHERMTU;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ IFQ_SET_READY(&ifp->if_snd);
+ if_attachhead(ifp);
+
if_alloc_sadl(ifp);
+ bcopy(&sc->sc_ac.ac_enaddr, LLADDR(ifp->if_sadl), ifp->if_addrlen);
+ LIST_INIT(&sc->sc_ac.ac_multiaddrs);
#if NBPFILTER > 0
- bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
#endif
return (0);
}
@@ -667,44 +735,22 @@
{
struct carp_softc *sc = ifp->if_softc;
struct carp_if *cif;
- struct ip_moptions *imo = &sc->sc_imo;
-#ifdef INET6
- struct ip6_moptions *im6o = &sc->sc_im6o;
-#endif

timeout_del(&sc->sc_ad_tmo);
timeout_del(&sc->sc_md_tmo);
timeout_del(&sc->sc_md6_tmo);

- if (sc->sc_ifp != NULL) {
- cif = (struct carp_if *)sc->sc_ifp->if_carp;
+ if (sc->sc_carpdev != NULL) {
+ cif = (struct carp_if *)sc->sc_carpdev->if_carp;
TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
if (cif->vhif_nvrs) {
- ifpromisc(sc->sc_ifp, 0);

- /* Clear IPv4 multicast */
- in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
- imo->imo_multicast_ifp = NULL;
-
- /* Clear IPv6 multicast */
-#ifdef INET6
- while (!LIST_EMPTY(&im6o->im6o_memberships)) {
- struct in6_multi_mship *imm =
- LIST_FIRST(&im6o->im6o_memberships);
-
- LIST_REMOVE(imm, i6mm_chain);
- in6_leavegroup(imm);
- }
-#endif
-
- sc->sc_ifp->if_carp = NULL;
+ sc->sc_carpdev->if_carp = NULL;
FREE(cif, M_IFADDR);
}
}

-#if NBPFILTER > 0
- bpfdetach(ifp);
-#endif
+ ether_ifdetach(ifp);
if_detach(ifp);
free(sc, M_DEVBUF);

@@ -714,25 +760,27 @@
void
carpdetach(struct carp_softc *sc)
{
- struct ifaddr *ifa;
+ struct carp_if *cif;

timeout_del(&sc->sc_ad_tmo);
timeout_del(&sc->sc_md_tmo);
timeout_del(&sc->sc_md6_tmo);

- while ((ifa = TAILQ_FIRST(&sc->sc_ac.ac_if.if_addrlist)) != NULL)
- if (ifa->ifa_addr->sa_family == AF_INET) {
- struct in_ifaddr *ia = ifatoia(ifa);
-
- carp_del_addr(sc, &ia->ia_addr);
-
- /* ripped screaming from in_control(SIOCDIFADDR) */
- in_ifscrub(&sc->sc_ac.ac_if, ia);
- TAILQ_REMOVE(&sc->sc_ac.ac_if.if_addrlist,
- ifa, ifa_list);
- TAILQ_REMOVE(&in_ifaddr, ia, ia_list);
- IFAFREE((&ia->ia_ifa));
+ carp_set_state(sc, INIT);
+ sc->sc_ac.ac_if.if_flags &= ~IFF_UP;
+ carp_setrun(sc, 0);
+ carp_multicast_cleanup(sc);
+
+ if (sc->sc_carpdev != NULL) {
+ cif = (struct carp_if *)sc->sc_carpdev->if_carp;
+ TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
+ if (!--cif->vhif_nvrs) {
+ ifpromisc(sc->sc_carpdev, 0);
+ sc->sc_carpdev->if_carp = NULL;
+ FREE(cif, M_IFADDR);
}
+ }
+ sc->sc_carpdev = NULL;
}

/* Detach an interface from the carp. */
@@ -786,7 +834,7 @@
struct carp_softc *vh;

TAILQ_FOREACH(ifp, &ifnet, if_list) {
- if (ifp->if_carp == NULL)
+ if (ifp->if_carp == NULL || ifp->if_type == IFT_CARP)
continue;

cif = (struct carp_if *)ifp->if_carp;
@@ -808,9 +856,16 @@
struct carp_header *ch_ptr;
struct mbuf *m;
int error, len, advbase, advskew, s;
+ struct ifaddr *ifa;
+ struct sockaddr sa;

s = splsoftnet();

+ if (sc->sc_carpdev == NULL) {
+ sc->sc_ac.ac_if.if_oerrors++;
+ goto retry_later;
+ }
+
/* bow out if we've lost our UPness or RUNNINGuiness */
if ((sc->sc_ac.ac_if.if_flags &
(IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
@@ -837,7 +892,7 @@


#ifdef INET
- if (sc->sc_ia) {
+ if (sc->sc_naddrs) {
struct ip *ip;

MGETHDR(m, M_DONTWAIT, MT_HEADER);
@@ -863,7 +918,15 @@
ip->ip_ttl = CARP_DFLTTL;
ip->ip_p = IPPROTO_CARP;
ip->ip_sum = 0;
- ip->ip_src.s_addr = sc->sc_ia->ia_addr.sin_addr.s_addr;
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_family = AF_INET;
+ ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
+ if (ifa == NULL)
+ ip->ip_src.s_addr = 0;
+ else
+ ip->ip_src.s_addr =
+ ifatoia(ifa)->ia_addr.sin_addr.s_addr;
ip->ip_dst.s_addr = INADDR_CARP_GROUP;

ch_ptr = (void *)ip + sizeof(*ip);
@@ -909,7 +972,7 @@
}
#endif /* INET */
#ifdef INET6
- if (sc->sc_ia6) {
+ if (sc->sc_naddrs6) {
struct ip6_hdr *ip6;

MGETHDR(m, M_DONTWAIT, MT_HEADER);
@@ -930,8 +993,16 @@
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_hlim = CARP_DFLTTL;
ip6->ip6_nxt = IPPROTO_CARP;
- bcopy(&sc->sc_ia6->ia_addr.sin6_addr, &ip6->ip6_src,
- sizeof(struct in6_addr));
+
+ /* set the source address */
+ bzero(&sa, sizeof(sa));
+ sa.sa_family = AF_INET6;
+ ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
+ if (ifa == NULL) /* This should never happen with IPv6 */
+ 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 */

ip6->ip6_dst.s6_addr8[0] = 0xff;
@@ -1004,7 +1075,7 @@
continue;

in = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
- arprequest(sc->sc_ifp, &in, &in, sc->sc_ac.ac_enaddr);
+ arprequest(sc->sc_carpdev, &in, &in, sc->sc_ac.ac_enaddr);
DELAY(1000); /* XXX */
}
splx(s);
@@ -1025,7 +1096,7 @@
continue;

in6 = &ifatoia6(ifa)->ia_addr.sin6_addr;
- nd6_na_output(sc->sc_ifp, &mcast, in6,
+ nd6_na_output(sc->sc_carpdev, &mcast, in6,
ND_NA_FLAG_OVERRIDE, 1, NULL);
DELAY(1000); /* XXX */
}
@@ -1178,23 +1249,67 @@
}
#endif /* INET6 */

-struct ifnet *
-carp_forus(void *v, void *dhost)
+int
+carp_input(struct ether_header *eh, struct mbuf *m)
{
- struct carp_if *cif = v;
+ struct carp_if *cif = (struct carp_if *)m->m_pkthdr.rcvif->if_carp;
struct carp_softc *vh;
- u_int8_t *ena = dhost;
+ u_int8_t *ena = (u_int8_t *)&eh->ether_dhost;
+ struct ifnet *ifp;
+
+ if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+ struct mbuf *m0;
+
+ /*
+ * XXX Should reall check the list of multicast addresses
+ * for each CARP interface _before_ copying.
+ */
+ TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+ m0 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
+ if (m0 == NULL)
+ continue;
+ m0->m_pkthdr.rcvif = &vh->sc_ac.ac_if;
+ ether_input(&vh->sc_ac.ac_if, eh, m0);
+ }
+ return (1);
+ }

if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1)
- return (NULL);
+ return (1);

TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list)
if ((vh->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
(IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER &&
- !bcmp(dhost, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
- return (&vh->sc_ac.ac_if);
+ !bcmp(ena, vh->sc_ac.ac_enaddr,
+ ETHER_ADDR_LEN))
+ break;

- return (NULL);
+ if (vh == NULL)
+ return (1);
+
+ m->m_pkthdr.rcvif = ifp = &vh->sc_ac.ac_if;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf) {
+ /*
+ * Do the usual BPF fakery. Note that we don't support
+ * promiscuous mode here, since it would require the
+ * drivers to know about CARP and we're not ready for
+ * that yet.
+ */
+ struct mbuf m0;
+
+ m0.m_flags = 0;
+ m0.m_next = m;
+ m0.m_len = ETHER_HDR_LEN;
+ m0.m_data = (char *)eh;
+ bpf_mtap(ifp->if_bpf, &m0);
+ }
+#endif
+ ifp->if_ipackets++;
+ ether_input(ifp, eh, m);
+
+ return (0);
}

void
@@ -1231,10 +1346,16 @@
{
struct timeval tv;

+ if (sc->sc_carpdev == NULL) {
+ sc->sc_ac.ac_if.if_flags &= ~IFF_RUNNING;
+ carp_set_state(sc, INIT);
+ return;
+ }
+
if (sc->sc_ac.ac_if.if_flags & IFF_UP &&
- sc->sc_vhid > 0 && (sc->sc_naddrs || sc->sc_naddrs6))
+ sc->sc_vhid > 0 && (sc->sc_naddrs || sc->sc_naddrs6)) {
sc->sc_ac.ac_if.if_flags |= IFF_RUNNING;
- else {
+ } else {
sc->sc_ac.ac_if.if_flags &= ~IFF_RUNNING;
carp_setroute(sc, RTM_DELETE);
return;
@@ -1287,15 +1408,120 @@
}
}

+void
+carp_multicast_cleanup(struct carp_softc *sc) {
+ struct ip_moptions *imo = &sc->sc_imo;
+ struct ip6_moptions *im6o = &sc->sc_im6o;
+
+ /* Clean up our own multicast memberships */
+ while (imo->imo_num_memberships > 0) {
+ if (imo->imo_membership[--imo->imo_num_memberships] == NULL)
+ in_delmulti(imo->imo_membership[imo->imo_num_memberships]);
+ imo->imo_membership[imo->imo_num_memberships] = NULL;
+ }
+ imo->imo_multicast_ifp = NULL;
+
+ while (!LIST_EMPTY(&im6o->im6o_memberships)) {
+ struct in6_multi_mship *imm =
+ LIST_FIRST(&im6o->im6o_memberships);
+
+ LIST_REMOVE(imm, i6mm_chain);
+ in6_leavegroup(imm);
+ }
+ im6o->im6o_multicast_ifp = NULL;
+
+ /* And any other multicast memberships */
+ carp_ether_purgemulti(sc);
+}
+
+int
+carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp)
+{
+ struct carp_if *cif, *ncif = NULL;
+ struct carp_softc *vr, *after = NULL;
+ int myself = 0, error = 0;
+
+ if (ifp == sc->sc_carpdev)
+ return (0);
+
+ if (ifp != NULL) {
+ if ((ifp->if_flags & IFF_MULTICAST) == 0)
+ return (EADDRNOTAVAIL);
+
+ if (ifp->if_carp == NULL) {
+ MALLOC(ncif, struct carp_if *, sizeof(*cif),
+ M_IFADDR, M_WAITOK);
+ if (!ncif)
+ return (ENOBUFS);
+ if ((error = ifpromisc(ifp, 1))) {
+ FREE(ncif, M_IFADDR);
+ return (error);
+ }
+
+ ncif->vhif_ifp = ifp;
+ TAILQ_INIT(&ncif->vhif_vrs);
+ } else {
+ cif = (struct carp_if *)ifp->if_carp;
+ TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
+ if (vr != sc && vr->sc_vhid == sc->sc_vhid)
+ return (EINVAL);
+ }
+
+ /* detach from old interface */
+ if (sc->sc_carpdev != NULL)
+ carpdetach(sc);
+
+ /* join multicast groups */
+ if (sc->sc_naddrs < 0 &&
+ (error = carp_join_multicast(sc, ifp)) != 0) {
+ FREE(ncif, M_IFADDR);
+ return (error);
+ }
+
+ if (sc->sc_naddrs6 < 0 &&
+ (error = carp_join_multicast(sc, ifp)) != 0) {
+ FREE(ncif, M_IFADDR);
+ return (error);
+ }
+
+ /* attach carp interface to physical interface */
+ if (ncif != NULL)
+ ifp->if_carp = (caddr_t)ncif;
+ sc->sc_carpdev = ifp;
+ cif = (struct carp_if *)ifp->if_carp;
+ TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
+ if (vr == sc)
+ myself = 1;
+ if (vr->sc_vhid < sc->sc_vhid)
+ after = vr;
+ }
+
+ if (!myself) {
+ /* We're trying to keep things in order */
+ if (after == NULL) {
+ TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
+ } else {
+ TAILQ_INSERT_AFTER(&cif->vhif_vrs, after,
+ sc, sc_list);
+ }
+ cif->vhif_nvrs++;
+ }
+ if (sc->sc_naddrs || sc->sc_naddrs6)
+ sc->sc_ac.ac_if.if_flags |= IFF_UP;
+ } else {
+ carpdetach(sc);
+ sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
+ }
+ return (0);
+
+}
+
int
carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
{
- struct ifnet *ifp;
- struct carp_if *cif;
+ struct ifnet *ifp = sc->sc_carpdev;
struct in_ifaddr *ia, *ia_if;
- struct ip_moptions *imo = &sc->sc_imo;
- struct in_addr addr;
- int own, error;
+ int own, error = 0;

if (sin->sin_addr.s_addr == 0) {
if (!(sc->sc_ac.ac_if.if_flags & IFF_UP))
@@ -1308,7 +1534,8 @@

/* we have to do it by hands to check we won't match on us */
ia_if = NULL; own = 0;
- for (ia = TAILQ_FIRST(&in_ifaddr); ia; ia = TAILQ_NEXT(ia, ia_list)) {
+ for (ia = TAILQ_FIRST(&in_ifaddr); ia;
+ ia = TAILQ_NEXT(ia, ia_list)) {

/* and, yeah, we need a multicast-capable iface too */
if (ia->ia_ifp != &sc->sc_ac.ac_if &&
@@ -1322,127 +1549,66 @@
}
}

- if (!ia_if)
- return (EADDRNOTAVAIL);
- ia = ia_if;
- ifp = ia->ia_ifp;
-
- if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 ||
- (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp))
- return (EADDRNOTAVAIL);
-
- if (imo->imo_num_memberships == 0) {
- addr.s_addr = INADDR_CARP_GROUP;
- if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == NULL)
- return (ENOBUFS);
- imo->imo_num_memberships++;
- imo->imo_multicast_ifp = ifp;
- imo->imo_multicast_ttl = CARP_DFLTTL;
- imo->imo_multicast_loop = 0;
- }
-
- if (!ifp->if_carp) {
-
- MALLOC(cif, struct carp_if *, sizeof(*cif), M_IFADDR, M_WAITOK);
- if (!cif) {
- error = ENOBUFS;
- goto cleanup;
- }
- if ((error = ifpromisc(ifp, 1))) {
- FREE(cif, M_IFADDR);
- goto cleanup;
- }
-
- bzero(cif, sizeof(*cif));
- cif->vhif_ifp = ifp;
- TAILQ_INIT(&cif->vhif_vrs);
- ifp->if_carp = (caddr_t)cif;
-
- } else {
- struct carp_softc *vr;
+ if (ia_if) {
+ ia = ia_if;
+ if (ifp) {
+ if (ifp != ia->ia_ifp)
+ return (EADDRNOTAVAIL);
+ } else {
+ ifp = ia->ia_ifp;
+ }
+ }

- cif = (struct carp_if *)ifp->if_carp;
- TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
- if (vr != sc && vr->sc_vhid == sc->sc_vhid) {
- error = EINVAL;
- goto cleanup;
- }
- }
- sc->sc_ia = ia;
- sc->sc_ifp = ifp;
+ if ((error = carp_set_ifp(sc, ifp)))
+ return (error);

- { /* XXX prevent endless loop if already in queue */
- struct carp_softc *vr, *after = NULL;
- int myself = 0;
- cif = (struct carp_if *)ifp->if_carp;
-
- TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
- if (vr == sc)
- myself = 1;
- if (vr->sc_vhid < sc->sc_vhid)
- after = vr;
- }
+ if (sc->sc_carpdev == NULL)
+ return (EADDRNOTAVAIL);

- if (!myself) {
- /* We're trying to keep things in order */
- if (after == NULL) {
- TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
- } else {
- TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list);
- }
- cif->vhif_nvrs++;
- }
- }
+ if (sc->sc_naddrs == 0 && (error = carp_join_multicast(sc, ifp)) != 0)
+ return (error);

sc->sc_naddrs++;
- sc->sc_ac.ac_if.if_flags |= IFF_UP;
+ if (sc->sc_carpdev != NULL)
+ sc->sc_ac.ac_if.if_flags |= IFF_UP;
+
if (own)
sc->sc_advskew = 0;
carp_set_state(sc, INIT);
carp_setrun(sc, 0);

return (0);
-
-cleanup:
- in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
- return (error);
}

int
-carp_del_addr(struct carp_softc *sc, struct sockaddr_in *sin)
+carp_join_multicast(struct carp_softc *sc, struct ifnet *ifp)
{
- int error = 0;
-
- if (!--sc->sc_naddrs) {
- struct carp_if *cif = (struct carp_if *)sc->sc_ifp->if_carp;
- struct ip_moptions *imo = &sc->sc_imo;
+ struct ip_moptions *imo = &sc->sc_imo, tmpimo;
+ struct in_addr addr;

- timeout_del(&sc->sc_ad_tmo);
- sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
- sc->sc_vhid = -1;
- in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
- imo->imo_multicast_ifp = NULL;
- TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
- if (!--cif->vhif_nvrs) {
- sc->sc_ifp->if_carp = NULL;
- FREE(cif, M_IFADDR);
- }
+ bzero(&tmpimo, sizeof(tmpimo));
+ addr.s_addr = INADDR_CARP_GROUP;
+ if ((tmpimo.imo_membership[0] =
+ in_addmulti(&addr, &sc->sc_ac.ac_if)) == NULL) {
+ return (ENOBUFS);
}

- return (error);
+ imo->imo_membership[0] = tmpimo.imo_membership[0];
+ imo->imo_num_memberships = 1;
+ imo->imo_multicast_ifp = &sc->sc_ac.ac_if;
+ imo->imo_multicast_ttl = CARP_DFLTTL;
+ imo->imo_multicast_loop = 0;
+ return (0);
}

+
#ifdef INET6
int
carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
{
- struct ifnet *ifp;
- struct carp_if *cif;
+ struct ifnet *ifp = sc->sc_carpdev;
struct in6_ifaddr *ia, *ia_if;
- struct ip6_moptions *im6o = &sc->sc_im6o;
- struct in6_multi_mship *imm;
- struct sockaddr_in6 addr;
- int own, error;
+ int own, error = 0;

if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
if (!(sc->sc_ac.ac_if.if_flags & IFF_UP))
@@ -1477,143 +1643,84 @@
}
}

- if (!ia_if)
- return (EADDRNOTAVAIL);
- ia = ia_if;
- ifp = ia->ia_ifp;
-
- if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 ||
- (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp != ifp))
- return (EADDRNOTAVAIL);
-
- if (!sc->sc_naddrs6) {
- im6o->im6o_multicast_ifp = ifp;
-
- /* join CARP multicast address */
- bzero(&addr, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_len = sizeof(addr);
- addr.sin6_addr.s6_addr16[0] = htons(0xff02);
- addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
- addr.sin6_addr.s6_addr8[15] = 0x12;
- if ((imm = in6_joingroup(ifp, &addr.sin6_addr, &error)) == NULL)
- goto cleanup;
- LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
-
- /* join solicited multicast address */
- bzero(&addr.sin6_addr, sizeof(addr.sin6_addr));
- addr.sin6_addr.s6_addr16[0] = htons(0xff02);
- addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
- addr.sin6_addr.s6_addr32[1] = 0;
- addr.sin6_addr.s6_addr32[2] = htonl(1);
- addr.sin6_addr.s6_addr32[3] = sin6->sin6_addr.s6_addr32[3];
- addr.sin6_addr.s6_addr8[12] = 0xff;
- if ((imm = in6_joingroup(ifp, &addr.sin6_addr, &error)) == NULL)
- goto cleanup;
- LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
- }
-
- if (!ifp->if_carp) {
- MALLOC(cif, struct carp_if *, sizeof(*cif), M_IFADDR, M_WAITOK);
- if (!cif) {
- error = ENOBUFS;
- goto cleanup;
- }
- if ((error = ifpromisc(ifp, 1))) {
- FREE(cif, M_IFADDR);
- goto cleanup;
+ if (ia_if) {
+ ia = ia_if;
+ if (sc->sc_carpdev) {
+ if (sc->sc_carpdev != ia->ia_ifp)
+ return (EADDRNOTAVAIL);
+ } else {
+ ifp = ia->ia_ifp;
}
-
- bzero(cif, sizeof(*cif));
- cif->vhif_ifp = ifp;
- TAILQ_INIT(&cif->vhif_vrs);
- ifp->if_carp = (caddr_t)cif;
-
- } else {
- struct carp_softc *vr;
-
- cif = (struct carp_if *)ifp->if_carp;
- TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
- if (vr != sc && vr->sc_vhid == sc->sc_vhid) {
- error = EINVAL;
- goto cleanup;
- }
}
- sc->sc_ia6 = ia;
- sc->sc_ifp = ifp;

- { /* XXX prevent endless loop if already in queue */
- struct carp_softc *vr, *after = NULL;
- int myself = 0;
- cif = (struct carp_if *)ifp->if_carp;
+ if ((error = carp_set_ifp(sc, ifp)))
+ return (error);

- TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
- if (vr == sc)
- myself = 1;
- if (vr->sc_vhid < sc->sc_vhid)
- after = vr;
- }
+ if (sc->sc_carpdev == NULL)
+ return (EADDRNOTAVAIL);

- if (!myself) {
- /* We're trying to keep things in order */
- if (after == NULL) {
- TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
- } else {
- TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list);
- }
- cif->vhif_nvrs++;
- }
- }
+ if (sc->sc_naddrs6 == 0 && (error = carp_join_multicast6(sc, ifp)) != 0)
+ return (error);

sc->sc_naddrs6++;
- sc->sc_ac.ac_if.if_flags |= IFF_UP;
- if (own)
- sc->sc_advskew = 0;
+ if (sc->sc_carpdev != NULL)
+ sc->sc_ac.ac_if.if_flags |= IFF_UP;
carp_set_state(sc, INIT);
carp_setrun(sc, 0);

return (0);
-
-cleanup:
- /* clean up multicast memberships */
- if (!sc->sc_naddrs6) {
- while (!LIST_EMPTY(&im6o->im6o_memberships)) {
- imm = LIST_FIRST(&im6o->im6o_memberships);
- LIST_REMOVE(imm, i6mm_chain);
- in6_leavegroup(imm);
- }
- }
- return (error);
}

int
-carp_del_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
+carp_join_multicast6(struct carp_softc *sc, struct ifnet *ifp)
{
- int error = 0;
-
- if (!--sc->sc_naddrs6) {
- struct carp_if *cif = (struct carp_if *)sc->sc_ifp->if_carp;
- struct ip6_moptions *im6o = &sc->sc_im6o;
+ struct in6_multi_mship *imm, *imm2;
+ struct ip6_moptions *im6o = &sc->sc_im6o;
+ struct sockaddr_in6 addr6;
+ int error;
+
+ /*
+ * For IPv6, we can attach to the physical interface, as
+ * there will be a link-local address there.
+ * This way we don't need a link-local address on the
+ * CARP interface.
+ */

- timeout_del(&sc->sc_ad_tmo);
- sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
- sc->sc_vhid = -1;
- while (!LIST_EMPTY(&im6o->im6o_memberships)) {
- struct in6_multi_mship *imm =
- LIST_FIRST(&im6o->im6o_memberships);
+ /* Join IPv6 CARP multicast group */
+ bzero(&addr6, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_len = sizeof(addr6);
+ addr6.sin6_addr.s6_addr16[0] = htons(0xff02);
+ addr6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
+ addr6.sin6_addr.s6_addr8[15] = 0x12;
+ if ((imm = in6_joingroup(ifp,
+ &addr6.sin6_addr, &error)) == NULL) {
+ return (error);
+ }
+ /* join solicited multicast address */
+ bzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr));
+ addr6.sin6_addr.s6_addr16[0] = htons(0xff02);
+ addr6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
+ addr6.sin6_addr.s6_addr32[1] = 0;
+ addr6.sin6_addr.s6_addr32[2] = htonl(1);
+ addr6.sin6_addr.s6_addr32[3] = 0;
+ addr6.sin6_addr.s6_addr8[12] = 0xff;
+ if ((imm2 = in6_joingroup(ifp,
+ &addr6.sin6_addr, &error)) == NULL) {
+ in6_leavegroup(imm);
+ return (error);
+ }
+
+ /* apply v6 multicast membership */
+ im6o->im6o_multicast_ifp = sc->sc_carpdev;
+ if (imm)
+ LIST_INSERT_HEAD(&im6o->im6o_memberships, imm,
+ i6mm_chain);
+ if (imm2)
+ LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2,
+ i6mm_chain);

- LIST_REMOVE(imm, i6mm_chain);
- in6_leavegroup(imm);
- }
- im6o->im6o_multicast_ifp = NULL;
- TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
- if (!--cif->vhif_nvrs) {
- sc->sc_ifp->if_carp = NULL;
- FREE(cif, M_IFADDR);
- }
- }
-
- return (error);
+ return (0);
}

#endif /* INET6 */
@@ -1627,6 +1734,7 @@
struct ifaddr *ifa;
struct ifreq *ifr;
struct ifaliasreq *ifra;
+ struct ifnet *cdev = NULL;
int error = 0;

ifa = (struct ifaddr *)addr;
@@ -1683,12 +1791,12 @@
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
- error = carp_del_addr(sc, satosin(&ifra->ifra_addr));
+ sc->sc_naddrs--;
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- error = carp_del_addr6(sc, satosin6(&ifra->ifra_addr));
+ sc->sc_naddrs6--;
break;
#endif /* INET6 */
default:
@@ -1719,6 +1827,11 @@
if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr)))
break;
error = 1;
+ if (carpr.carpr_carpdev[0] != '\0' &&
+ (cdev = ifunit(carpr.carpr_carpdev)) == NULL)
+ return (EINVAL);
+ if ((error = carp_set_ifp(sc, cdev)))
+ return (error);
if (sc->sc_state != INIT && carpr.carpr_state != sc->sc_state) {
switch (carpr.carpr_state) {
case BACKUP:
@@ -1739,9 +1852,9 @@
error = EINVAL;
break;
}
- if (sc->sc_ifp) {
+ if (sc->sc_carpdev) {
struct carp_if *cif;
- cif = (struct carp_if *)sc->sc_ifp->if_carp;
+ cif = (struct carp_if *)sc->sc_carpdev->if_carp;
TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
if (vr != sc &&
vr->sc_vhid == carpr.carpr_vhid)
@@ -1754,6 +1867,8 @@
sc->sc_ac.ac_enaddr[3] = 0;
sc->sc_ac.ac_enaddr[4] = 1;
sc->sc_ac.ac_enaddr[5] = sc->sc_vhid;
+ bcopy(&sc->sc_ac.ac_enaddr,
+ LLADDR(ifp->if_sadl), ifp->if_addrlen);
error--;
}
if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) {
@@ -1780,6 +1895,9 @@

case SIOCGVH:
bzero(&carpr, sizeof(carpr));
+ if (sc->sc_carpdev != NULL)
+ strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname,
+ IFNAMSIZ);
carpr.carpr_state = sc->sc_state;
carpr.carpr_vhid = sc->sc_vhid;
carpr.carpr_advbase = sc->sc_advbase;
@@ -1790,6 +1908,14 @@
error = copyout(&carpr, ifr->ifr_data, sizeof(carpr));
break;

+ case SIOCADDMULTI:
+ error = carp_ether_addmulti(sc, ifr);
+ break;
+
+ case SIOCDELMULTI:
+ error = carp_ether_delmulti(sc, ifr);
+ break;
+
default:
error = EINVAL;
}
@@ -1841,7 +1967,7 @@
sc = carp_ifp->if_softc;

/* Set the source MAC address to Virtual Router MAC Address */
- switch (ifp->if_type) {
+ switch (sc->sc_carpdev->if_type) {
#if NETHER > 0
case IFT_ETHER: {
struct ether_header *eh;
@@ -1886,7 +2012,7 @@
#endif
default:
printf("%s: carp is not supported for this interface type\n",
- ifp->if_xname);
+ sc->sc_carpdev->if_xname);
return (EOPNOTSUPP);
}

@@ -1921,8 +2047,8 @@
struct carp_softc *sc;

TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
- if (sc->sc_ifp->if_link_state == LINK_STATE_DOWN ||
- !(sc->sc_ifp->if_flags & IFF_UP)) {
+ if (sc->sc_carpdev->if_link_state == LINK_STATE_DOWN ||
+ !(sc->sc_carpdev->if_flags & IFF_UP)) {
sc->sc_flags_backup = sc->sc_ac.ac_if.if_flags;
sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
timeout_del(&sc->sc_ad_tmo);
@@ -1944,5 +2070,131 @@
carp_suppress_preempt--;
sc->sc_suppress = 0;
}
+ }
+}
+
+
+int
+carp_ether_addmulti(struct carp_softc *sc, struct ifreq *ifr)
+{
+ struct ifnet *ifp;
+ struct carp_mc_entry *mc;
+ u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
+ int error;
+
+ ifp = sc->sc_carpdev;
+ if (ifp == NULL)
+ return (EINVAL);
+
+ error = ether_addmulti(ifr, (struct arpcom *)&sc->sc_ac);
+ if (error != ENETRESET)
+ return (error);
+
+ /*
+ * This is new multicast address. We have to tell parent
+ * about it. Also, remember this multicast address so that
+ * we can delete them on unconfigure.
+ */
+ MALLOC(mc, struct carp_mc_entry *, sizeof(struct carp_mc_entry),
+ M_DEVBUF, M_NOWAIT);
+ if (mc == NULL) {
+ error = ENOMEM;
+ goto alloc_failed;
+ }
+
+ /*
+ * As ether_addmulti() returns ENETRESET, following two
+ * statement shouldn't fail.
+ */
+ (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
+ ETHER_LOOKUP_MULTI(addrlo, addrhi, &sc->sc_ac, mc->mc_enm);
+ memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
+ LIST_INSERT_HEAD(&sc->carp_mc_listhead, mc, mc_entries);
+
+ error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
+ if (error != 0)
+ goto ioctl_failed;
+
+ return (error);
+
+ ioctl_failed:
+ LIST_REMOVE(mc, mc_entries);
+ FREE(mc, M_DEVBUF);
+ alloc_failed:
+ (void)ether_delmulti(ifr, (struct arpcom *)&sc->sc_ac);
+
+ return (error);
+}
+
+int
+carp_ether_delmulti(struct carp_softc *sc, struct ifreq *ifr)
+{
+ struct ifnet *ifp;
+ struct ether_multi *enm;
+ struct carp_mc_entry *mc;
+ u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
+ int error;
+
+ ifp = sc->sc_carpdev;
+ if (ifp == NULL)
+ return (EINVAL);
+
+ /*
+ * Find a key to lookup carp_mc_entry. We have to do this
+ * before calling ether_delmulti for obvious reason.
+ */
+ if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
+ return (error);
+ ETHER_LOOKUP_MULTI(addrlo, addrhi, &sc->sc_ac, enm);
+
+ error = ether_delmulti(ifr, (struct arpcom *)&sc->sc_ac);
+ if (error != ENETRESET)
+ return (error);
+
+ /* We no longer use this multicast address. Tell parent so. */
+ error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
+ if (error == 0) {
+ /* And forget about this address. */
+ for (mc = LIST_FIRST(&sc->carp_mc_listhead); mc != NULL;
+ mc = LIST_NEXT(mc, mc_entries)) {
+ if (mc->mc_enm == enm) {
+ LIST_REMOVE(mc, mc_entries);
+ FREE(mc, M_DEVBUF);
+ break;
+ }
+ }
+ KASSERT(mc != NULL);
+ } else
+ (void)ether_addmulti(ifr, (struct arpcom *)&sc->sc_ac);
+ return (error);
+}
+
+/*
+ * Delete any multicast address we have asked to add from parent
+ * interface. Called when the carp is being unconfigured.
+ */
+void
+carp_ether_purgemulti(struct carp_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_carpdev; /* Parent. */
+ struct carp_mc_entry *mc;
+ union {
+ struct ifreq ifreq;
+ struct {
+ char ifr_name[IFNAMSIZ];
+ struct sockaddr_storage ifr_ss;
+ } ifreq_storage;
+ } ifreq;
+ struct ifreq *ifr = &ifreq.ifreq;
+
+ if (ifp == NULL)
+ return;
+
+ memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
+ while ((mc = LIST_FIRST(&sc->carp_mc_listhead)) != NULL) {
+ memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
+ (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
+ LIST_REMOVE(mc, mc_entries);
+ FREE(mc, M_DEVBUF);
}
}
Index: sys/netinet/ip_carp.h
================================================== =================
RCS file: /cvs/src/sys/netinet/ip_carp.h,v
retrieving revision 1.8
diff -u -r1.8 ip_carp.h
--- sys/netinet/ip_carp.h 29 Jul 2004 22:12:15 -0000 1.8
+++ sys/netinet/ip_carp.h 6 Dec 2004 20:41:12 -0000
@@ -109,6 +109,13 @@
u_int64_t carps_preempt; /* if enabled, preemptions */
};

+#define CARPDEVNAMSIZ 16
+#ifdef IFNAMSIZ
+#if CARPDEVNAMSIZ != IFNAMSIZ
+#error
+#endif
+#endif
+
/*
* Configuration structure for SIOCSVH SIOCGVH
*/
@@ -116,6 +123,8 @@
int carpr_state;
#define CARP_STATES "INIT", "BACKUP", "MASTER"
#define CARP_MAXSTATE 2
+
+ char carpr_carpdev[CARPDEVNAMSIZ];
int carpr_vhid;
int carpr_advskew;
int carpr_advbase;
@@ -143,15 +152,15 @@

#ifdef _KERNEL
void carp_ifdetach (struct ifnet *);
-void carp_input (struct mbuf *, ...);
+void carp_proto_input (struct mbuf *, ...);
void carp_carpdev_state(void *);
-int carp6_input (struct mbuf **, int *, int);
-int carp_output (struct ifnet *, struct mbuf *, struct sockaddr *,
+int carp6_proto_input(struct mbuf **, int *, int);
+int carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
-int carp_iamatch (void *, struct in_ifaddr *, struct in_addr *,
+int carp_iamatch(void *, struct in_ifaddr *, struct in_addr *,
u_int8_t **);
struct ifaddr *carp_iamatch6(void *, struct in6_addr *);
void *carp_macmatch6(void *, struct mbuf *, struct in6_addr *);
-struct ifnet *carp_forus (void *, void *);
-int carp_sysctl (int *, u_int, void *, size_t *, void *, size_t);
+int carp_input(struct ether_header *, struct mbuf *);
+int carp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
#endif
Index: sys/netinet/in_proto.c
================================================== =================
RCS file: /cvs/src/sys/netinet/in_proto.c,v
retrieving revision 1.41
diff -u -r1.41 in_proto.c
--- sys/netinet/in_proto.c 17 Sep 2004 11:32:53 -0000 1.41
+++ sys/netinet/in_proto.c 20 Nov 2004 17:59:21 -0000
@@ -292,7 +292,7 @@
#endif /* NGRE > 0 */
#if NCARP > 0
{ SOCK_RAW, &inetdomain, IPPROTO_CARP, PR_ATOMIC|PR_ADDR,
- carp_input, rip_output, 0, rip_ctloutput,
+ carp_proto_input, rip_output, 0, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0, carp_sysctl
},
Index: sys/netinet6/in6_proto.c
================================================== =================
RCS file: /cvs/src/sys/netinet6/in6_proto.c,v
retrieving revision 1.45
diff -u -r1.45 in6_proto.c
--- sys/netinet6/in6_proto.c 18 Oct 2004 03:59:33 -0000 1.45
+++ sys/netinet6/in6_proto.c 20 Nov 2004 17:59:21 -0000
@@ -220,7 +220,7 @@
},
#if NCARP > 0
{ SOCK_RAW, &inet6domain, IPPROTO_CARP, PR_ATOMIC|PR_ADDR,
- carp6_input, rip6_output, 0, rip6_ctloutput,
+ carp6_proto_input, rip6_output, 0, rip6_ctloutput,
rip6_usrreq,
0, 0, 0, 0, carp_sysctl
},
Index: sys/netinet6/in6_ifattach.c
================================================== =================
RCS file: /cvs/src/sys/netinet6/in6_ifattach.c,v
retrieving revision 1.36
diff -u -r1.36 in6_ifattach.c
--- sys/netinet6/in6_ifattach.c 7 May 2004 14:42:27 -0000 1.36
+++ sys/netinet6/in6_ifattach.c 20 Nov 2004 17:59:21 -0000
@@ -577,6 +577,7 @@
case IFT_ENC:
case IFT_PFLOG:
case IFT_PFSYNC:
+ case IFT_CARP:
return;
case IFT_PROPVIRTUAL:
if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
Index: sbin/ifconfig/ifconfig.c
================================================== =================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.121
diff -u -r1.121 ifconfig.c
--- sbin/ifconfig/ifconfig.c 1 Dec 2004 15:57:44 -0000 1.121
+++ sbin/ifconfig/ifconfig.c 6 Dec 2004 20:07:53 -0000
@@ -203,6 +203,8 @@
void setcarp_passwd(const char *, int);
void setcarp_vhid(const char *, int);
void setcarp_state(const char *, int);
+void setcarpdev(const char *, int);
+void unsetcarpdev(const char *, int);
void setpfsync_syncif(const char *, int);
void setpfsync_maxupd(const char *, int);
void unsetpfsync_syncif(const char *, int);
@@ -304,6 +306,8 @@
{ "pass", NEXTARG, 0, setcarp_passwd },
{ "vhid", NEXTARG, 0, setcarp_vhid },
{ "state", NEXTARG, 0, setcarp_state },
+ { "carpdev", NEXTARG, 0, setcarpdev },
+ { "-carpdev", 1, 0, unsetcarpdev },
{ "syncif", NEXTARG, 0, setpfsync_syncif },
{ "-syncif", 1, 0, unsetpfsync_syncif },
{ "syncpeer", NEXTARG, 0, setpfsync_syncpeer },
@@ -2875,9 +2879,10 @@
else
state = carp_states[carpr.carpr_state];

- printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
- state, carpr.carpr_vhid, carpr.carpr_advbase,
- carpr.carpr_advskew);
+ printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n",
+ state, carpr.carpr_carpdev[0] != '\0' ?
+ carpr.carpr_carpdev : "none", carpr.carpr_vhid,
+ carpr.carpr_advbase, carpr.carpr_advskew);
}
}

@@ -2997,6 +3002,40 @@
}

/* ARGSUSED */
+void
+setcarpdev(const char *val, int d)
+{
+ struct carpreq carpr;
+
+ bzero((char *)&carpr, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGVH");
+
+ strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev));
+
+ if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVH");
+}
+
+void
+unsetcarpdev(const char *val, int d)
+{
+ struct carpreq carpr;
+
+ bzero((char *)&carpr, sizeof(struct carpreq));
+ ifr.ifr_data = (caddr_t)&carpr;
+
+ if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGVH");
+
+ bzero((char *)&carpr.carpr_carpdev, sizeof(carpr.carpr_carpdev));
+
+ if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVH");
+}
+
void
setpfsync_syncif(const char *val, int d)
{
Index: sys/net/if.c
================================================== =================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.95
diff -u -r1.95 if.c
--- sys/net/if.c 4 Dec 2004 16:16:45 -0000 1.95
+++ sys/net/if.c 5 Dec 2004 03:31:36 -0000
@@ -79,6 +79,7 @@

#include <net/if.h>
#include <net/if_dl.h>
+#include <net/if_types.h>
#include <net/route.h>

#ifdef INET
@@ -485,7 +486,7 @@

#if NCARP > 0
/* Remove the interface from any carp group it is a part of. */
- if (ifp->if_carp)
+ if (ifp->if_carp && ifp->if_type != IFT_CARP)
carp_ifdetach(ifp);
#endif

Index: sys/net/if.h
================================================== =================
RCS file: /cvs/src/sys/net/if.h,v
retrieving revision 1.60
diff -u -r1.60 if.h
--- sys/net/if.h 3 Dec 2004 17:31:03 -0000 1.60
+++ sys/net/if.h 6 Dec 2004 21:20:53 -0000
@@ -180,7 +180,12 @@
int if_pcount; /* number of promiscuous listeners */
caddr_t if_bpf; /* packet filter structure */
caddr_t if_bridge; /* bridge structure */
- caddr_t if_carp; /* carp structure */
+ union {
+ caddr_t carp_s; /* carp structure (used by !carp ifs) */
+ struct ifnet *carp_d; /* ptr to carpdev (used by carp ifs) */
+ } if_carp_ptr;
+#define if_carp if_carp_ptr.carp_s
+#define if_carpdev if_carp_ptr.carp_d
u_short if_index; /* numeric abbreviation for this if */
short if_timer; /* time 'til if_watchdog called */
short if_flags; /* up/down, broadcast, etc. */

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 06:15 AM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
UnixAdminTalk.com

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405