1 /* $NetBSD: ip_carp.c,v 1.38 2009/06/07 06:11:18 taca Exp $ */
2 /* $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $ */
5 * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
6 * Copyright (c) 2003 Ryan McBride. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.38 2009/06/07 06:11:18 taca Exp $");
36 * - support for hardware checksum calculations;
40 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/callout.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/device.h>
50 #include <sys/kernel.h>
51 #include <sys/kauth.h>
52 #include <sys/sysctl.h>
53 #include <sys/ucred.h>
54 #include <sys/syslog.h>
61 #include <net/if_types.h>
62 #include <net/if_ether.h>
63 #include <net/route.h>
64 #include <net/netisr.h>
65 #include <net/net_stats.h>
66 #include <netinet/if_inarp.h>
68 #include <machine/stdarg.h>
71 #include <net/if_fddi.h>
74 #include <net/if_token.h>
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/in_var.h>
81 #include <netinet/ip.h>
82 #include <netinet/ip_var.h>
84 #include <net/if_dl.h>
88 #include <netinet/icmp6.h>
89 #include <netinet/ip6.h>
90 #include <netinet6/ip6_var.h>
91 #include <netinet6/nd6.h>
92 #include <netinet6/scope6_var.h>
100 #include <sys/sha1.h>
102 #include <netinet/ip_carp.h>
104 struct carp_mc_entry
{
105 LIST_ENTRY(carp_mc_entry
) mc_entries
;
107 struct ether_multi
*mcu_enm
;
109 struct sockaddr_storage mc_addr
;
111 #define mc_enm mc_u.mcu_enm
114 struct ethercom sc_ac
;
115 #define sc_if sc_ac.ec_if
116 #define sc_carpdev sc_ac.ec_if.if_carpdev
119 struct ip_moptions sc_imo
;
121 struct ip6_moptions sc_im6o
;
123 TAILQ_ENTRY(carp_softc
) sc_list
;
125 enum { INIT
= 0, BACKUP
, MASTER
} sc_state
;
130 int sc_sendad_errors
;
131 #define CARP_SENDAD_MAX_ERRORS 3
132 int sc_sendad_success
;
133 #define CARP_SENDAD_MIN_SUCCESS 3
139 int sc_advbase
; /* seconds */
141 u_int64_t sc_counter
;
144 #define CARP_HMAC_PAD 64
145 unsigned char sc_key
[CARP_KEY_LEN
];
146 unsigned char sc_pad
[CARP_HMAC_PAD
];
148 u_int32_t sc_hashkey
[2];
150 struct callout sc_ad_tmo
; /* advertisement timeout */
151 struct callout sc_md_tmo
; /* master down timeout */
152 struct callout sc_md6_tmo
; /* master down timeout */
154 LIST_HEAD(__carp_mchead
, carp_mc_entry
) carp_mc_listhead
;
157 int carp_suppress_preempt
= 0;
158 int carp_opts
[CARPCTL_MAXID
] = { 0, 1, 0, 0, 0 }; /* XXX for now */
160 static percpu_t
*carpstat_percpu
;
162 #define CARP_STATINC(x) _NET_STATINC(carpstat_percpu, x)
165 TAILQ_HEAD(, carp_softc
) vhif_vrs
;
168 struct ifnet
*vhif_ifp
;
171 #define CARP_LOG(sc, s) \
172 if (carp_opts[CARPCTL_LOG]) { \
174 log(LOG_INFO, "%s: ", \
175 (sc)->sc_if.if_xname); \
177 log(LOG_INFO, "carp: "); \
182 void carp_hmac_prepare(struct carp_softc
*);
183 void carp_hmac_generate(struct carp_softc
*, u_int32_t
*,
185 int carp_hmac_verify(struct carp_softc
*, u_int32_t
*,
187 void carp_setroute(struct carp_softc
*, int);
188 void carp_proto_input_c(struct mbuf
*, struct carp_header
*, sa_family_t
);
189 void carpattach(int);
190 void carpdetach(struct carp_softc
*);
191 int carp_prepare_ad(struct mbuf
*, struct carp_softc
*,
192 struct carp_header
*);
193 void carp_send_ad_all(void);
194 void carp_send_ad(void *);
195 void carp_send_arp(struct carp_softc
*);
196 void carp_master_down(void *);
197 int carp_ioctl(struct ifnet
*, u_long
, void *);
198 void carp_start(struct ifnet
*);
199 void carp_setrun(struct carp_softc
*, sa_family_t
);
200 void carp_set_state(struct carp_softc
*, int);
201 int carp_addrcount(struct carp_if
*, struct in_ifaddr
*, int);
202 enum { CARP_COUNT_MASTER
, CARP_COUNT_RUNNING
};
204 void carp_multicast_cleanup(struct carp_softc
*);
205 int carp_set_ifp(struct carp_softc
*, struct ifnet
*);
206 void carp_set_enaddr(struct carp_softc
*);
207 void carp_addr_updated(void *);
208 u_int32_t
carp_hash(struct carp_softc
*, u_char
*);
209 int carp_set_addr(struct carp_softc
*, struct sockaddr_in
*);
210 int carp_join_multicast(struct carp_softc
*);
212 void carp_send_na(struct carp_softc
*);
213 int carp_set_addr6(struct carp_softc
*, struct sockaddr_in6
*);
214 int carp_join_multicast6(struct carp_softc
*);
216 int carp_clone_create(struct if_clone
*, int);
217 int carp_clone_destroy(struct ifnet
*);
218 int carp_ether_addmulti(struct carp_softc
*, struct ifreq
*);
219 int carp_ether_delmulti(struct carp_softc
*, struct ifreq
*);
220 void carp_ether_purgemulti(struct carp_softc
*);
222 static void sysctl_net_inet_carp_setup(struct sysctllog
**);
224 struct if_clone carp_cloner
=
225 IF_CLONE_INITIALIZER("carp", carp_clone_create
, carp_clone_destroy
);
227 static __inline u_int16_t
228 carp_cksum(struct mbuf
*m
, int len
)
230 return (in_cksum(m
, len
));
234 carp_hmac_prepare(struct carp_softc
*sc
)
236 u_int8_t carp_version
= CARP_VERSION
, type
= CARP_ADVERTISEMENT
;
237 u_int8_t vhid
= sc
->sc_vhid
& 0xff;
242 struct in_addr last
, cur
, in
;
244 struct in6_addr last6
, cur6
, in6
;
247 /* compute ipad from key */
248 memset(sc
->sc_pad
, 0, sizeof(sc
->sc_pad
));
249 memcpy(sc
->sc_pad
, sc
->sc_key
, sizeof(sc
->sc_key
));
250 for (i
= 0; i
< sizeof(sc
->sc_pad
); i
++)
251 sc
->sc_pad
[i
] ^= 0x36;
253 /* precompute first part of inner hash */
254 SHA1Init(&sc
->sc_sha1
);
255 SHA1Update(&sc
->sc_sha1
, sc
->sc_pad
, sizeof(sc
->sc_pad
));
256 SHA1Update(&sc
->sc_sha1
, (void *)&carp_version
, sizeof(carp_version
));
257 SHA1Update(&sc
->sc_sha1
, (void *)&type
, sizeof(type
));
259 /* generate a key for the arpbalance hash, before the vhid is hashed */
260 memcpy(&sha1ctx
, &sc
->sc_sha1
, sizeof(sha1ctx
));
261 SHA1Final((unsigned char *)kmd
, &sha1ctx
);
262 sc
->sc_hashkey
[0] = kmd
[0] ^ kmd
[1];
263 sc
->sc_hashkey
[1] = kmd
[2] ^ kmd
[3];
265 /* the rest of the precomputation */
266 SHA1Update(&sc
->sc_sha1
, (void *)&vhid
, sizeof(vhid
));
268 /* Hash the addresses from smallest to largest, not interface order */
274 cur
.s_addr
= 0xffffffff;
275 IFADDR_FOREACH(ifa
, &sc
->sc_if
) {
276 in
.s_addr
= ifatoia(ifa
)->ia_addr
.sin_addr
.s_addr
;
277 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
278 ntohl(in
.s_addr
) > ntohl(last
.s_addr
) &&
279 ntohl(in
.s_addr
) < ntohl(cur
.s_addr
)) {
280 cur
.s_addr
= in
.s_addr
;
285 SHA1Update(&sc
->sc_sha1
, (void *)&cur
, sizeof(cur
));
290 memset(&cur6
, 0x00, sizeof(cur6
));
294 memset(&cur6
, 0xff, sizeof(cur6
));
295 IFADDR_FOREACH(ifa
, &sc
->sc_if
) {
296 in6
= ifatoia6(ifa
)->ia_addr
.sin6_addr
;
297 if (IN6_IS_ADDR_LINKLOCAL(&in6
))
298 in6
.s6_addr16
[1] = 0;
299 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&&
300 memcmp(&in6
, &last6
, sizeof(in6
)) > 0 &&
301 memcmp(&in6
, &cur6
, sizeof(in6
)) < 0) {
307 SHA1Update(&sc
->sc_sha1
, (void *)&cur6
, sizeof(cur6
));
311 /* convert ipad to opad */
312 for (i
= 0; i
< sizeof(sc
->sc_pad
); i
++)
313 sc
->sc_pad
[i
] ^= 0x36 ^ 0x5c;
317 carp_hmac_generate(struct carp_softc
*sc
, u_int32_t counter
[2],
318 unsigned char md
[20])
322 /* fetch first half of inner hash */
323 memcpy(&sha1ctx
, &sc
->sc_sha1
, sizeof(sha1ctx
));
325 SHA1Update(&sha1ctx
, (void *)counter
, sizeof(sc
->sc_counter
));
326 SHA1Final(md
, &sha1ctx
);
330 SHA1Update(&sha1ctx
, sc
->sc_pad
, sizeof(sc
->sc_pad
));
331 SHA1Update(&sha1ctx
, md
, 20);
332 SHA1Final(md
, &sha1ctx
);
336 carp_hmac_verify(struct carp_softc
*sc
, u_int32_t counter
[2],
337 unsigned char md
[20])
339 unsigned char md2
[20];
341 carp_hmac_generate(sc
, counter
, md2
);
343 return (memcmp(md
, md2
, sizeof(md2
)));
347 carp_setroute(struct carp_softc
*sc
, int cmd
)
353 IFADDR_FOREACH(ifa
, &sc
->sc_if
) {
354 switch (ifa
->ifa_addr
->sa_family
) {
358 int hr_otherif
, nr_ourif
;
361 * Avoid screwing with the routes if there are other
362 * carp interfaces which are master and have the same
365 if (sc
->sc_carpdev
!= NULL
&&
366 sc
->sc_carpdev
->if_carp
!= NULL
) {
367 count
= carp_addrcount(
368 (struct carp_if
*)sc
->sc_carpdev
->if_carp
,
369 ifatoia(ifa
), CARP_COUNT_MASTER
);
370 if ((cmd
== RTM_ADD
&& count
!= 1) ||
371 (cmd
== RTM_DELETE
&& count
!= 0))
375 /* Remove the existing host route, if any */
376 rtrequest(RTM_DELETE
, ifa
->ifa_addr
,
377 ifa
->ifa_addr
, ifa
->ifa_netmask
,
381 (void)rtrequest(RTM_GET
, ifa
->ifa_addr
, ifa
->ifa_addr
,
382 ifa
->ifa_netmask
, RTF_HOST
, &rt
);
383 hr_otherif
= (rt
&& rt
->rt_ifp
!= &sc
->sc_if
&&
384 rt
->rt_flags
& (RTF_CLONING
|RTF_CLONED
));
390 /* Check for a network route on our interface */
393 (void)rtrequest(RTM_GET
, ifa
->ifa_addr
, ifa
->ifa_addr
,
394 ifa
->ifa_netmask
, 0, &rt
);
395 nr_ourif
= (rt
&& rt
->rt_ifp
== &sc
->sc_if
);
400 ifa
->ifa_rtrequest
= NULL
;
401 ifa
->ifa_flags
&= ~RTF_CLONING
;
403 rtrequest(RTM_ADD
, ifa
->ifa_addr
,
404 ifa
->ifa_addr
, ifa
->ifa_netmask
,
405 RTF_UP
| RTF_HOST
, NULL
);
407 if (!hr_otherif
|| nr_ourif
|| !rt
) {
408 if (nr_ourif
&& !(rt
->rt_flags
&
410 rtrequest(RTM_DELETE
,
413 ifa
->ifa_netmask
, 0, NULL
);
415 ifa
->ifa_rtrequest
= arp_rtrequest
;
416 ifa
->ifa_flags
|= RTF_CLONING
;
418 if (rtrequest(RTM_ADD
, ifa
->ifa_addr
,
419 ifa
->ifa_addr
, ifa
->ifa_netmask
, 0,
421 ifa
->ifa_flags
|= IFA_ROUTE
;
452 * process input packet.
453 * we have rearranged checks order compared to the rfc,
454 * but it seems more efficient this way or not possible otherwise.
457 carp_proto_input(struct mbuf
*m
, ...)
459 struct ip
*ip
= mtod(m
, struct ip
*);
460 struct carp_softc
*sc
= NULL
;
461 struct carp_header
*ch
;
462 int iplen
, len
, hlen
;
466 hlen
= va_arg(ap
, int);
469 CARP_STATINC(CARP_STAT_IPACKETS
);
471 if (!carp_opts
[CARPCTL_ALLOW
]) {
476 /* check if received on a valid carp interface */
477 if (m
->m_pkthdr
.rcvif
->if_type
!= IFT_CARP
) {
478 CARP_STATINC(CARP_STAT_BADIF
);
479 CARP_LOG(sc
, ("packet received on non-carp interface: %s",
480 m
->m_pkthdr
.rcvif
->if_xname
));
485 /* verify that the IP TTL is 255. */
486 if (ip
->ip_ttl
!= CARP_DFLTTL
) {
487 CARP_STATINC(CARP_STAT_BADTTL
);
488 CARP_LOG(sc
, ("received ttl %d != %d on %s", ip
->ip_ttl
,
489 CARP_DFLTTL
, m
->m_pkthdr
.rcvif
->if_xname
));
495 * verify that the received packet length is
496 * equal to the CARP header
498 iplen
= ip
->ip_hl
<< 2;
499 len
= iplen
+ sizeof(*ch
);
500 if (len
> m
->m_pkthdr
.len
) {
501 CARP_STATINC(CARP_STAT_BADLEN
);
502 CARP_LOG(sc
, ("packet too short %d on %s", m
->m_pkthdr
.len
,
503 m
->m_pkthdr
.rcvif
->if_xname
));
508 if ((m
= m_pullup(m
, len
)) == NULL
) {
509 CARP_STATINC(CARP_STAT_HDROPS
);
512 ip
= mtod(m
, struct ip
*);
513 ch
= (struct carp_header
*)((char *)ip
+ iplen
);
514 /* verify the CARP checksum */
516 if (carp_cksum(m
, len
- iplen
)) {
517 CARP_STATINC(CARP_STAT_BADSUM
);
518 CARP_LOG(sc
, ("checksum failed on %s",
519 m
->m_pkthdr
.rcvif
->if_xname
));
525 carp_proto_input_c(m
, ch
, AF_INET
);
530 carp6_proto_input(struct mbuf
**mp
, int *offp
, int proto
)
532 struct mbuf
*m
= *mp
;
533 struct carp_softc
*sc
= NULL
;
534 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
535 struct carp_header
*ch
;
538 CARP_STATINC(CARP_STAT_IPACKETS6
);
540 if (!carp_opts
[CARPCTL_ALLOW
]) {
542 return (IPPROTO_DONE
);
545 /* check if received on a valid carp interface */
546 if (m
->m_pkthdr
.rcvif
->if_type
!= IFT_CARP
) {
547 CARP_STATINC(CARP_STAT_BADIF
);
548 CARP_LOG(sc
, ("packet received on non-carp interface: %s",
549 m
->m_pkthdr
.rcvif
->if_xname
));
551 return (IPPROTO_DONE
);
554 /* verify that the IP TTL is 255 */
555 if (ip6
->ip6_hlim
!= CARP_DFLTTL
) {
556 CARP_STATINC(CARP_STAT_BADTTL
);
557 CARP_LOG(sc
, ("received ttl %d != %d on %s", ip6
->ip6_hlim
,
558 CARP_DFLTTL
, m
->m_pkthdr
.rcvif
->if_xname
));
560 return (IPPROTO_DONE
);
563 /* verify that we have a complete carp packet */
565 IP6_EXTHDR_GET(ch
, struct carp_header
*, m
, *offp
, sizeof(*ch
));
567 CARP_STATINC(CARP_STAT_BADLEN
);
568 CARP_LOG(sc
, ("packet size %u too small", len
));
569 return (IPPROTO_DONE
);
573 /* verify the CARP checksum */
575 if (carp_cksum(m
, sizeof(*ch
))) {
576 CARP_STATINC(CARP_STAT_BADSUM
);
577 CARP_LOG(sc
, ("checksum failed, on %s",
578 m
->m_pkthdr
.rcvif
->if_xname
));
580 return (IPPROTO_DONE
);
584 carp_proto_input_c(m
, ch
, AF_INET6
);
585 return (IPPROTO_DONE
);
590 carp_proto_input_c(struct mbuf
*m
, struct carp_header
*ch
, sa_family_t af
)
592 struct carp_softc
*sc
;
593 u_int64_t tmp_counter
;
594 struct timeval sc_tv
, ch_tv
;
596 TAILQ_FOREACH(sc
, &((struct carp_if
*)
597 m
->m_pkthdr
.rcvif
->if_carpdev
->if_carp
)->vhif_vrs
, sc_list
)
598 if (sc
->sc_vhid
== ch
->carp_vhid
)
601 if (!sc
|| (sc
->sc_if
.if_flags
& (IFF_UP
|IFF_RUNNING
)) !=
602 (IFF_UP
|IFF_RUNNING
)) {
603 CARP_STATINC(CARP_STAT_BADVHID
);
609 * Check if our own advertisement was duplicated
610 * from a non simplex interface.
611 * XXX If there is no address on our physical interface
612 * there is no way to distinguish our ads from the ones
613 * another carp host might have sent us.
615 if ((sc
->sc_carpdev
->if_flags
& IFF_SIMPLEX
) == 0) {
619 memset(&sa
, 0, sizeof(sa
));
621 ifa
= ifaof_ifpforaddr(&sa
, sc
->sc_carpdev
);
623 if (ifa
&& af
== AF_INET
) {
624 struct ip
*ip
= mtod(m
, struct ip
*);
625 if (ip
->ip_src
.s_addr
==
626 ifatoia(ifa
)->ia_addr
.sin_addr
.s_addr
) {
632 if (ifa
&& af
== AF_INET6
) {
633 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
634 struct in6_addr in6_src
, in6_found
;
636 in6_src
= ip6
->ip6_src
;
637 in6_found
= ifatoia6(ifa
)->ia_addr
.sin6_addr
;
638 if (IN6_IS_ADDR_LINKLOCAL(&in6_src
))
639 in6_src
.s6_addr16
[1] = 0;
640 if (IN6_IS_ADDR_LINKLOCAL(&in6_found
))
641 in6_found
.s6_addr16
[1] = 0;
642 if (IN6_ARE_ADDR_EQUAL(&in6_src
, &in6_found
)) {
650 nanotime(&sc
->sc_if
.if_lastchange
);
651 sc
->sc_if
.if_ipackets
++;
652 sc
->sc_if
.if_ibytes
+= m
->m_pkthdr
.len
;
654 /* verify the CARP version. */
655 if (ch
->carp_version
!= CARP_VERSION
) {
656 CARP_STATINC(CARP_STAT_BADVER
);
657 sc
->sc_if
.if_ierrors
++;
658 CARP_LOG(sc
, ("invalid version %d != %d",
659 ch
->carp_version
, CARP_VERSION
));
664 /* verify the hash */
665 if (carp_hmac_verify(sc
, ch
->carp_counter
, ch
->carp_md
)) {
666 CARP_STATINC(CARP_STAT_BADAUTH
);
667 sc
->sc_if
.if_ierrors
++;
668 CARP_LOG(sc
, ("incorrect hash"));
673 tmp_counter
= ntohl(ch
->carp_counter
[0]);
674 tmp_counter
= tmp_counter
<<32;
675 tmp_counter
+= ntohl(ch
->carp_counter
[1]);
677 /* XXX Replay protection goes here */
679 sc
->sc_init_counter
= 0;
680 sc
->sc_counter
= tmp_counter
;
683 sc_tv
.tv_sec
= sc
->sc_advbase
;
684 if (carp_suppress_preempt
&& sc
->sc_advskew
< 240)
685 sc_tv
.tv_usec
= 240 * 1000000 / 256;
687 sc_tv
.tv_usec
= sc
->sc_advskew
* 1000000 / 256;
688 ch_tv
.tv_sec
= ch
->carp_advbase
;
689 ch_tv
.tv_usec
= ch
->carp_advskew
* 1000000 / 256;
691 switch (sc
->sc_state
) {
696 * If we receive an advertisement from a backup who's going to
697 * be more frequent than us, go into BACKUP state.
699 if (timercmp(&sc_tv
, &ch_tv
, >) ||
700 timercmp(&sc_tv
, &ch_tv
, ==)) {
701 callout_stop(&sc
->sc_ad_tmo
);
702 CARP_LOG(sc
, ("MASTER -> BACKUP (more frequent advertisement received)"));
703 carp_set_state(sc
, BACKUP
);
705 carp_setroute(sc
, RTM_DELETE
);
710 * If we're pre-empting masters who advertise slower than us,
711 * and this one claims to be slower, treat him as down.
713 if (carp_opts
[CARPCTL_PREEMPT
] && timercmp(&sc_tv
, &ch_tv
, <)) {
714 CARP_LOG(sc
, ("BACKUP -> MASTER (preempting a slower master)"));
715 carp_master_down(sc
);
720 * If the master is going to advertise at such a low frequency
721 * that he's guaranteed to time out, we'd might as well just
722 * treat him as timed out now.
724 sc_tv
.tv_sec
= sc
->sc_advbase
* 3;
725 if (timercmp(&sc_tv
, &ch_tv
, <)) {
726 CARP_LOG(sc
, ("BACKUP -> MASTER (master timed out)"));
727 carp_master_down(sc
);
732 * Otherwise, we reset the counter and wait for the next
744 * Interface side of the CARP implementation.
751 if_clone_attach(&carp_cloner
);
753 carpstat_percpu
= percpu_alloc(sizeof(uint64_t) * CARP_NSTATS
);
757 carp_clone_create(struct if_clone
*ifc
, int unit
)
759 extern int ifqmaxlen
;
760 struct carp_softc
*sc
;
763 sc
= malloc(sizeof(*sc
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
768 sc
->sc_advbase
= CARP_DFLTINTV
;
769 sc
->sc_vhid
= -1; /* required setting */
771 sc
->sc_init_counter
= 1;
772 sc
->sc_naddrs
= sc
->sc_naddrs6
= 0;
774 sc
->sc_im6o
.im6o_multicast_hlim
= CARP_DFLTTL
;
777 callout_init(&sc
->sc_ad_tmo
, 0);
778 callout_init(&sc
->sc_md_tmo
, 0);
779 callout_init(&sc
->sc_md6_tmo
, 0);
781 callout_setfunc(&sc
->sc_ad_tmo
, carp_send_ad
, sc
);
782 callout_setfunc(&sc
->sc_md_tmo
, carp_master_down
, sc
);
783 callout_setfunc(&sc
->sc_md6_tmo
, carp_master_down
, sc
);
785 LIST_INIT(&sc
->carp_mc_listhead
);
788 snprintf(ifp
->if_xname
, sizeof ifp
->if_xname
, "%s%d", ifc
->ifc_name
,
790 ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
;
791 ifp
->if_ioctl
= carp_ioctl
;
792 ifp
->if_start
= carp_start
;
793 ifp
->if_output
= carp_output
;
794 ifp
->if_type
= IFT_CARP
;
795 ifp
->if_addrlen
= ETHER_ADDR_LEN
;
796 ifp
->if_hdrlen
= ETHER_HDR_LEN
;
797 ifp
->if_mtu
= ETHERMTU
;
798 IFQ_SET_MAXLEN(&ifp
->if_snd
, ifqmaxlen
);
799 IFQ_SET_READY(&ifp
->if_snd
);
803 ifp
->if_broadcastaddr
= etherbroadcastaddr
;
805 LIST_INIT(&sc
->sc_ac
.ec_multiaddrs
);
807 bpfattach(ifp
, DLT_EN10MB
, ETHER_HDR_LEN
);
813 carp_clone_destroy(struct ifnet
*ifp
)
815 struct carp_softc
*sc
= ifp
->if_softc
;
817 carpdetach(ifp
->if_softc
);
820 callout_destroy(&sc
->sc_ad_tmo
);
821 callout_destroy(&sc
->sc_md_tmo
);
822 callout_destroy(&sc
->sc_md6_tmo
);
823 free(ifp
->if_softc
, M_DEVBUF
);
829 carpdetach(struct carp_softc
*sc
)
834 callout_stop(&sc
->sc_ad_tmo
);
835 callout_stop(&sc
->sc_md_tmo
);
836 callout_stop(&sc
->sc_md6_tmo
);
839 carp_suppress_preempt
--;
842 if (sc
->sc_sendad_errors
>= CARP_SENDAD_MAX_ERRORS
)
843 carp_suppress_preempt
--;
844 sc
->sc_sendad_errors
= 0;
846 carp_set_state(sc
, INIT
);
847 sc
->sc_if
.if_flags
&= ~IFF_UP
;
849 carp_multicast_cleanup(sc
);
852 if (sc
->sc_carpdev
!= NULL
) {
853 /* XXX linkstatehook removal */
854 cif
= (struct carp_if
*)sc
->sc_carpdev
->if_carp
;
855 TAILQ_REMOVE(&cif
->vhif_vrs
, sc
, sc_list
);
856 if (!--cif
->vhif_nvrs
) {
857 ifpromisc(sc
->sc_carpdev
, 0);
858 sc
->sc_carpdev
->if_carp
= NULL
;
862 sc
->sc_carpdev
= NULL
;
866 /* Detach an interface from the carp. */
868 carp_ifdetach(struct ifnet
*ifp
)
870 struct carp_softc
*sc
, *nextsc
;
871 struct carp_if
*cif
= (struct carp_if
*)ifp
->if_carp
;
873 for (sc
= TAILQ_FIRST(&cif
->vhif_vrs
); sc
; sc
= nextsc
) {
874 nextsc
= TAILQ_NEXT(sc
, sc_list
);
880 carp_prepare_ad(struct mbuf
*m
, struct carp_softc
*sc
,
881 struct carp_header
*ch
)
883 if (sc
->sc_init_counter
) {
884 /* this could also be seconds since unix epoch */
885 sc
->sc_counter
= arc4random();
886 sc
->sc_counter
= sc
->sc_counter
<< 32;
887 sc
->sc_counter
+= arc4random();
891 ch
->carp_counter
[0] = htonl((sc
->sc_counter
>>32)&0xffffffff);
892 ch
->carp_counter
[1] = htonl(sc
->sc_counter
&0xffffffff);
894 carp_hmac_generate(sc
, ch
->carp_counter
, ch
->carp_md
);
900 carp_send_ad_all(void)
904 struct carp_softc
*vh
;
906 TAILQ_FOREACH(ifp
, &ifnet
, if_list
) {
907 if (ifp
->if_carp
== NULL
|| ifp
->if_type
== IFT_CARP
)
910 cif
= (struct carp_if
*)ifp
->if_carp
;
911 TAILQ_FOREACH(vh
, &cif
->vhif_vrs
, sc_list
) {
912 if ((vh
->sc_if
.if_flags
& (IFF_UP
|IFF_RUNNING
)) ==
913 (IFF_UP
|IFF_RUNNING
) && vh
->sc_state
== MASTER
)
921 carp_send_ad(void *v
)
923 struct carp_header ch
;
925 struct carp_softc
*sc
= v
;
926 struct carp_header
*ch_ptr
;
928 int error
, len
, advbase
, advskew
, s
;
934 advbase
= advskew
= 0; /* Sssssh compiler */
935 if (sc
->sc_carpdev
== NULL
) {
936 sc
->sc_if
.if_oerrors
++;
940 /* bow out if we've gone to backup (the carp interface is going down) */
941 if (sc
->sc_bow_out
) {
946 advbase
= sc
->sc_advbase
;
947 if (!carp_suppress_preempt
|| sc
->sc_advskew
> 240)
948 advskew
= sc
->sc_advskew
;
952 tv
.tv_usec
= advskew
* 1000000 / 256;
955 ch
.carp_version
= CARP_VERSION
;
956 ch
.carp_type
= CARP_ADVERTISEMENT
;
957 ch
.carp_vhid
= sc
->sc_vhid
;
958 ch
.carp_advbase
= advbase
;
959 ch
.carp_advskew
= advskew
;
960 ch
.carp_authlen
= 7; /* XXX DEFINE */
961 ch
.carp_pad1
= 0; /* must be zero */
969 MGETHDR(m
, M_DONTWAIT
, MT_HEADER
);
971 sc
->sc_if
.if_oerrors
++;
972 CARP_STATINC(CARP_STAT_ONOMEM
);
973 /* XXX maybe less ? */
976 len
= sizeof(*ip
) + sizeof(ch
);
977 m
->m_pkthdr
.len
= len
;
978 m
->m_pkthdr
.rcvif
= NULL
;
980 MH_ALIGN(m
, m
->m_len
);
981 m
->m_flags
|= M_MCAST
;
982 ip
= mtod(m
, struct ip
*);
983 ip
->ip_v
= IPVERSION
;
984 ip
->ip_hl
= sizeof(*ip
) >> 2;
985 ip
->ip_tos
= IPTOS_LOWDELAY
;
986 ip
->ip_len
= htons(len
);
987 ip
->ip_id
= 0; /* no need for id, we don't support fragments */
988 ip
->ip_off
= htons(IP_DF
);
989 ip
->ip_ttl
= CARP_DFLTTL
;
990 ip
->ip_p
= IPPROTO_CARP
;
993 memset(&sa
, 0, sizeof(sa
));
994 sa
.sa_family
= AF_INET
;
995 ifa
= ifaof_ifpforaddr(&sa
, sc
->sc_carpdev
);
997 ip
->ip_src
.s_addr
= 0;
1000 ifatoia(ifa
)->ia_addr
.sin_addr
.s_addr
;
1001 ip
->ip_dst
.s_addr
= INADDR_CARP_GROUP
;
1003 ch_ptr
= (struct carp_header
*)(&ip
[1]);
1004 memcpy(ch_ptr
, &ch
, sizeof(ch
));
1005 if (carp_prepare_ad(m
, sc
, ch_ptr
))
1008 m
->m_data
+= sizeof(*ip
);
1009 ch_ptr
->carp_cksum
= carp_cksum(m
, len
- sizeof(*ip
));
1010 m
->m_data
-= sizeof(*ip
);
1012 nanotime(&sc
->sc_if
.if_lastchange
);
1013 sc
->sc_if
.if_opackets
++;
1014 sc
->sc_if
.if_obytes
+= len
;
1015 CARP_STATINC(CARP_STAT_OPACKETS
);
1017 error
= ip_output(m
, NULL
, NULL
, IP_RAWOUTPUT
, &sc
->sc_imo
,
1020 if (error
== ENOBUFS
)
1021 CARP_STATINC(CARP_STAT_ONOMEM
);
1023 CARP_LOG(sc
, ("ip_output failed: %d", error
));
1024 sc
->sc_if
.if_oerrors
++;
1025 if (sc
->sc_sendad_errors
< INT_MAX
)
1026 sc
->sc_sendad_errors
++;
1027 if (sc
->sc_sendad_errors
== CARP_SENDAD_MAX_ERRORS
) {
1028 carp_suppress_preempt
++;
1029 if (carp_suppress_preempt
== 1)
1032 sc
->sc_sendad_success
= 0;
1034 if (sc
->sc_sendad_errors
>= CARP_SENDAD_MAX_ERRORS
) {
1035 if (++sc
->sc_sendad_success
>=
1036 CARP_SENDAD_MIN_SUCCESS
) {
1037 carp_suppress_preempt
--;
1038 sc
->sc_sendad_errors
= 0;
1041 sc
->sc_sendad_errors
= 0;
1046 if (sc
->sc_naddrs6
) {
1047 struct ip6_hdr
*ip6
;
1049 MGETHDR(m
, M_DONTWAIT
, MT_HEADER
);
1051 sc
->sc_if
.if_oerrors
++;
1052 CARP_STATINC(CARP_STAT_ONOMEM
);
1053 /* XXX maybe less ? */
1056 len
= sizeof(*ip6
) + sizeof(ch
);
1057 m
->m_pkthdr
.len
= len
;
1058 m
->m_pkthdr
.rcvif
= NULL
;
1060 MH_ALIGN(m
, m
->m_len
);
1061 m
->m_flags
|= M_MCAST
;
1062 ip6
= mtod(m
, struct ip6_hdr
*);
1063 memset(ip6
, 0, sizeof(*ip6
));
1064 ip6
->ip6_vfc
|= IPV6_VERSION
;
1065 ip6
->ip6_hlim
= CARP_DFLTTL
;
1066 ip6
->ip6_nxt
= IPPROTO_CARP
;
1068 /* set the source address */
1069 memset(&sa
, 0, sizeof(sa
));
1070 sa
.sa_family
= AF_INET6
;
1071 ifa
= ifaof_ifpforaddr(&sa
, sc
->sc_carpdev
);
1072 if (ifa
== NULL
) /* This should never happen with IPv6 */
1073 memset(&ip6
->ip6_src
, 0, sizeof(struct in6_addr
));
1075 bcopy(ifatoia6(ifa
)->ia_addr
.sin6_addr
.s6_addr
,
1076 &ip6
->ip6_src
, sizeof(struct in6_addr
));
1077 /* set the multicast destination */
1079 ip6
->ip6_dst
.s6_addr16
[0] = htons(0xff02);
1080 ip6
->ip6_dst
.s6_addr8
[15] = 0x12;
1081 if (in6_setscope(&ip6
->ip6_dst
, sc
->sc_carpdev
, NULL
) != 0) {
1082 sc
->sc_if
.if_oerrors
++;
1084 CARP_LOG(sc
, ("in6_setscope failed"));
1088 ch_ptr
= (struct carp_header
*)(&ip6
[1]);
1089 memcpy(ch_ptr
, &ch
, sizeof(ch
));
1090 if (carp_prepare_ad(m
, sc
, ch_ptr
))
1093 m
->m_data
+= sizeof(*ip6
);
1094 ch_ptr
->carp_cksum
= carp_cksum(m
, len
- sizeof(*ip6
));
1095 m
->m_data
-= sizeof(*ip6
);
1097 nanotime(&sc
->sc_if
.if_lastchange
);
1098 sc
->sc_if
.if_opackets
++;
1099 sc
->sc_if
.if_obytes
+= len
;
1100 CARP_STATINC(CARP_STAT_OPACKETS6
);
1102 error
= ip6_output(m
, NULL
, NULL
, 0, &sc
->sc_im6o
, NULL
, NULL
);
1104 if (error
== ENOBUFS
)
1105 CARP_STATINC(CARP_STAT_ONOMEM
);
1107 CARP_LOG(sc
, ("ip6_output failed: %d", error
));
1108 sc
->sc_if
.if_oerrors
++;
1109 if (sc
->sc_sendad_errors
< INT_MAX
)
1110 sc
->sc_sendad_errors
++;
1111 if (sc
->sc_sendad_errors
== CARP_SENDAD_MAX_ERRORS
) {
1112 carp_suppress_preempt
++;
1113 if (carp_suppress_preempt
== 1)
1116 sc
->sc_sendad_success
= 0;
1118 if (sc
->sc_sendad_errors
>= CARP_SENDAD_MAX_ERRORS
) {
1119 if (++sc
->sc_sendad_success
>=
1120 CARP_SENDAD_MIN_SUCCESS
) {
1121 carp_suppress_preempt
--;
1122 sc
->sc_sendad_errors
= 0;
1125 sc
->sc_sendad_errors
= 0;
1132 if (advbase
!= 255 || advskew
!= 255)
1133 callout_schedule(&sc
->sc_ad_tmo
, tvtohz(&tv
));
1137 * Broadcast a gratuitous ARP request containing
1138 * the virtual router MAC address for each IP address
1139 * associated with the virtual router.
1142 carp_send_arp(struct carp_softc
*sc
)
1146 int s
= splsoftnet();
1148 IFADDR_FOREACH(ifa
, &sc
->sc_if
) {
1150 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
1153 in
= &ifatoia(ifa
)->ia_addr
.sin_addr
;
1154 arprequest(sc
->sc_carpdev
, in
, in
, CLLADDR(sc
->sc_if
.if_sadl
));
1155 DELAY(1000); /* XXX */
1162 carp_send_na(struct carp_softc
*sc
)
1165 struct in6_addr
*in6
;
1166 static struct in6_addr mcast
= IN6ADDR_LINKLOCAL_ALLNODES_INIT
;
1167 int s
= splsoftnet();
1169 IFADDR_FOREACH(ifa
, &sc
->sc_if
) {
1171 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
1174 in6
= &ifatoia6(ifa
)->ia_addr
.sin6_addr
;
1175 nd6_na_output(sc
->sc_carpdev
, &mcast
, in6
,
1176 ND_NA_FLAG_OVERRIDE
, 1, NULL
);
1177 DELAY(1000); /* XXX */
1184 * Based on bridge_hash() in if_bridge.c
1186 #define mix(a,b,c) \
1188 a -= b; a -= c; a ^= (c >> 13); \
1189 b -= c; b -= a; b ^= (a << 8); \
1190 c -= a; c -= b; c ^= (b >> 13); \
1191 a -= b; a -= c; a ^= (c >> 12); \
1192 b -= c; b -= a; b ^= (a << 16); \
1193 c -= a; c -= b; c ^= (b >> 5); \
1194 a -= b; a -= c; a ^= (c >> 3); \
1195 b -= c; b -= a; b ^= (a << 10); \
1196 c -= a; c -= b; c ^= (b >> 15); \
1200 carp_hash(struct carp_softc
*sc
, u_char
*src
)
1202 u_int32_t a
= 0x9e3779b9, b
= sc
->sc_hashkey
[0], c
= sc
->sc_hashkey
[1];
1204 c
+= sc
->sc_key
[3] << 24;
1205 c
+= sc
->sc_key
[2] << 16;
1206 c
+= sc
->sc_key
[1] << 8;
1220 carp_addrcount(struct carp_if
*cif
, struct in_ifaddr
*ia
, int type
)
1222 struct carp_softc
*vh
;
1226 TAILQ_FOREACH(vh
, &cif
->vhif_vrs
, sc_list
) {
1227 if ((type
== CARP_COUNT_RUNNING
&&
1228 (vh
->sc_if
.if_flags
& (IFF_UP
|IFF_RUNNING
)) ==
1229 (IFF_UP
|IFF_RUNNING
)) ||
1230 (type
== CARP_COUNT_MASTER
&& vh
->sc_state
== MASTER
)) {
1231 IFADDR_FOREACH(ifa
, &vh
->sc_if
) {
1232 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
1233 ia
->ia_addr
.sin_addr
.s_addr
==
1234 ifatoia(ifa
)->ia_addr
.sin_addr
.s_addr
)
1243 carp_iamatch(struct in_ifaddr
*ia
, u_char
*src
,
1244 u_int32_t
*count
, u_int32_t index
)
1246 struct carp_softc
*sc
= ia
->ia_ifp
->if_softc
;
1248 if (carp_opts
[CARPCTL_ARPBALANCE
]) {
1250 * We use the source ip to decide which virtual host should
1251 * handle the request. If we're master of that virtual host,
1252 * then we respond, otherwise, just drop the arp packet on
1256 /* Count the elegible carp interfaces with this address */
1258 *count
= carp_addrcount(
1259 (struct carp_if
*)ia
->ia_ifp
->if_carpdev
->if_carp
,
1260 ia
, CARP_COUNT_RUNNING
);
1262 /* This should never happen, but... */
1266 if (carp_hash(sc
, src
) % *count
== index
- 1 &&
1267 sc
->sc_state
== MASTER
) {
1271 if (sc
->sc_state
== MASTER
)
1280 carp_iamatch6(void *v
, struct in6_addr
*taddr
)
1282 struct carp_if
*cif
= v
;
1283 struct carp_softc
*vh
;
1286 TAILQ_FOREACH(vh
, &cif
->vhif_vrs
, sc_list
) {
1287 IFADDR_FOREACH(ifa
, &vh
->sc_if
) {
1288 if (IN6_ARE_ADDR_EQUAL(taddr
,
1289 &ifatoia6(ifa
)->ia_addr
.sin6_addr
) &&
1290 ((vh
->sc_if
.if_flags
& (IFF_UP
|IFF_RUNNING
)) ==
1291 (IFF_UP
|IFF_RUNNING
)) && vh
->sc_state
== MASTER
)
1301 carp_ourether(void *v
, struct ether_header
*eh
, u_char iftype
, int src
)
1303 struct carp_if
*cif
= (struct carp_if
*)v
;
1304 struct carp_softc
*vh
;
1308 ena
= (u_int8_t
*)&eh
->ether_shost
;
1310 ena
= (u_int8_t
*)&eh
->ether_dhost
;
1315 if (ena
[0] || ena
[1] || ena
[2] != 0x5e || ena
[3] || ena
[4] != 1)
1319 if (ena
[0] != 3 || ena
[1] || ena
[4] || ena
[5])
1327 TAILQ_FOREACH(vh
, &cif
->vhif_vrs
, sc_list
)
1328 if ((vh
->sc_if
.if_flags
& (IFF_UP
|IFF_RUNNING
)) ==
1329 (IFF_UP
|IFF_RUNNING
) && vh
->sc_state
== MASTER
&&
1330 !memcmp(ena
, CLLADDR(vh
->sc_if
.if_sadl
),
1332 return (&vh
->sc_if
);
1339 carp_input(struct mbuf
*m
, u_int8_t
*shost
, u_int8_t
*dhost
, u_int16_t etype
)
1341 struct ether_header eh
;
1342 struct carp_if
*cif
= (struct carp_if
*)m
->m_pkthdr
.rcvif
->if_carp
;
1345 memcpy(&eh
.ether_shost
, shost
, sizeof(eh
.ether_shost
));
1346 memcpy(&eh
.ether_dhost
, dhost
, sizeof(eh
.ether_dhost
));
1347 eh
.ether_type
= etype
;
1349 if (m
->m_flags
& (M_BCAST
|M_MCAST
)) {
1350 struct carp_softc
*vh
;
1354 * XXX Should really check the list of multicast addresses
1355 * for each CARP interface _before_ copying.
1357 TAILQ_FOREACH(vh
, &cif
->vhif_vrs
, sc_list
) {
1358 m0
= m_copym(m
, 0, M_COPYALL
, M_DONTWAIT
);
1361 m0
->m_pkthdr
.rcvif
= &vh
->sc_if
;
1362 ether_input(&vh
->sc_if
, m0
);
1367 ifp
= carp_ourether(cif
, &eh
, m
->m_pkthdr
.rcvif
->if_type
, 0);
1372 m
->m_pkthdr
.rcvif
= ifp
;
1376 bpf_mtap(ifp
->if_bpf
, m
);
1379 ether_input(ifp
, m
);
1384 carp_master_down(void *v
)
1386 struct carp_softc
*sc
= v
;
1388 switch (sc
->sc_state
) {
1390 printf("%s: master_down event in INIT state\n",
1391 sc
->sc_if
.if_xname
);
1396 CARP_LOG(sc
, ("INIT -> MASTER (preempting)"));
1397 carp_set_state(sc
, MASTER
);
1404 carp_setroute(sc
, RTM_ADD
);
1410 * When in backup state, af indicates whether to reset the master down timer
1411 * for v4 or v6. If it's set to zero, reset the ones which are already pending.
1414 carp_setrun(struct carp_softc
*sc
, sa_family_t af
)
1418 if (sc
->sc_carpdev
== NULL
) {
1419 sc
->sc_if
.if_flags
&= ~IFF_RUNNING
;
1420 carp_set_state(sc
, INIT
);
1424 if (sc
->sc_if
.if_flags
& IFF_UP
&& sc
->sc_vhid
> 0 &&
1425 (sc
->sc_naddrs
|| sc
->sc_naddrs6
) && !sc
->sc_suppress
) {
1426 sc
->sc_if
.if_flags
|= IFF_RUNNING
;
1428 sc
->sc_if
.if_flags
&= ~IFF_RUNNING
;
1429 carp_setroute(sc
, RTM_DELETE
);
1433 switch (sc
->sc_state
) {
1435 carp_set_state(sc
, BACKUP
);
1436 carp_setroute(sc
, RTM_DELETE
);
1440 callout_stop(&sc
->sc_ad_tmo
);
1441 tv
.tv_sec
= 3 * sc
->sc_advbase
;
1442 tv
.tv_usec
= sc
->sc_advskew
* 1000000 / 256;
1446 callout_schedule(&sc
->sc_md_tmo
, tvtohz(&tv
));
1451 callout_schedule(&sc
->sc_md6_tmo
, tvtohz(&tv
));
1456 callout_schedule(&sc
->sc_md_tmo
, tvtohz(&tv
));
1458 callout_schedule(&sc
->sc_md6_tmo
, tvtohz(&tv
));
1463 tv
.tv_sec
= sc
->sc_advbase
;
1464 tv
.tv_usec
= sc
->sc_advskew
* 1000000 / 256;
1465 callout_schedule(&sc
->sc_ad_tmo
, tvtohz(&tv
));
1471 carp_multicast_cleanup(struct carp_softc
*sc
)
1473 struct ip_moptions
*imo
= &sc
->sc_imo
;
1475 struct ip6_moptions
*im6o
= &sc
->sc_im6o
;
1477 u_int16_t n
= imo
->imo_num_memberships
;
1479 /* Clean up our own multicast memberships */
1481 if (imo
->imo_membership
[n
] != NULL
) {
1482 in_delmulti(imo
->imo_membership
[n
]);
1483 imo
->imo_membership
[n
] = NULL
;
1486 imo
->imo_num_memberships
= 0;
1487 imo
->imo_multicast_ifp
= NULL
;
1490 while (!LIST_EMPTY(&im6o
->im6o_memberships
)) {
1491 struct in6_multi_mship
*imm
=
1492 LIST_FIRST(&im6o
->im6o_memberships
);
1494 LIST_REMOVE(imm
, i6mm_chain
);
1495 in6_leavegroup(imm
);
1497 im6o
->im6o_multicast_ifp
= NULL
;
1500 /* And any other multicast memberships */
1501 carp_ether_purgemulti(sc
);
1505 carp_set_ifp(struct carp_softc
*sc
, struct ifnet
*ifp
)
1507 struct carp_if
*cif
, *ncif
= NULL
;
1508 struct carp_softc
*vr
, *after
= NULL
;
1509 int myself
= 0, error
= 0;
1512 if (ifp
== sc
->sc_carpdev
)
1516 if ((ifp
->if_flags
& IFF_MULTICAST
) == 0)
1517 return (EADDRNOTAVAIL
);
1519 if (ifp
->if_type
== IFT_CARP
)
1522 if (ifp
->if_carp
== NULL
) {
1523 ncif
= malloc(sizeof(*cif
), M_IFADDR
, M_NOWAIT
);
1526 if ((error
= ifpromisc(ifp
, 1))) {
1527 free(ncif
, M_IFADDR
);
1531 ncif
->vhif_ifp
= ifp
;
1532 TAILQ_INIT(&ncif
->vhif_vrs
);
1534 cif
= (struct carp_if
*)ifp
->if_carp
;
1535 TAILQ_FOREACH(vr
, &cif
->vhif_vrs
, sc_list
)
1536 if (vr
!= sc
&& vr
->sc_vhid
== sc
->sc_vhid
)
1540 /* detach from old interface */
1541 if (sc
->sc_carpdev
!= NULL
)
1544 /* join multicast groups */
1545 if (sc
->sc_naddrs
< 0 &&
1546 (error
= carp_join_multicast(sc
)) != 0) {
1548 free(ncif
, M_IFADDR
);
1553 if (sc
->sc_naddrs6
< 0 &&
1554 (error
= carp_join_multicast6(sc
)) != 0) {
1556 free(ncif
, M_IFADDR
);
1557 carp_multicast_cleanup(sc
);
1562 /* attach carp interface to physical interface */
1564 ifp
->if_carp
= (void *)ncif
;
1565 sc
->sc_carpdev
= ifp
;
1566 cif
= (struct carp_if
*)ifp
->if_carp
;
1567 TAILQ_FOREACH(vr
, &cif
->vhif_vrs
, sc_list
) {
1570 if (vr
->sc_vhid
< sc
->sc_vhid
)
1575 /* We're trying to keep things in order */
1576 if (after
== NULL
) {
1577 TAILQ_INSERT_TAIL(&cif
->vhif_vrs
, sc
, sc_list
);
1579 TAILQ_INSERT_AFTER(&cif
->vhif_vrs
, after
,
1584 if (sc
->sc_naddrs
|| sc
->sc_naddrs6
)
1585 sc
->sc_if
.if_flags
|= IFF_UP
;
1586 carp_set_enaddr(sc
);
1588 /* XXX linkstatehooks establish */
1589 carp_carpdev_state(ifp
);
1593 sc
->sc_if
.if_flags
&= ~(IFF_UP
|IFF_RUNNING
);
1599 carp_set_enaddr(struct carp_softc
*sc
)
1601 uint8_t enaddr
[ETHER_ADDR_LEN
];
1602 if (sc
->sc_carpdev
&& sc
->sc_carpdev
->if_type
== IFT_ISO88025
) {
1605 enaddr
[2] = 0x40 >> (sc
->sc_vhid
- 1);
1606 enaddr
[3] = 0x40000 >> (sc
->sc_vhid
- 1);
1615 enaddr
[5] = sc
->sc_vhid
;
1617 if_set_sadl(&sc
->sc_if
, enaddr
, sizeof(enaddr
), false);
1621 carp_addr_updated(void *v
)
1623 struct carp_softc
*sc
= (struct carp_softc
*) v
;
1625 int new_naddrs
= 0, new_naddrs6
= 0;
1627 IFADDR_FOREACH(ifa
, &sc
->sc_if
) {
1628 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
1630 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
1634 /* Handle a callback after SIOCDIFADDR */
1635 if (new_naddrs
< sc
->sc_naddrs
|| new_naddrs6
< sc
->sc_naddrs6
) {
1636 struct in_addr mc_addr
;
1637 struct in_multi
*inm
;
1639 sc
->sc_naddrs
= new_naddrs
;
1640 sc
->sc_naddrs6
= new_naddrs6
;
1642 /* Re-establish multicast membership removed by in_control */
1643 mc_addr
.s_addr
= INADDR_CARP_GROUP
;
1644 IN_LOOKUP_MULTI(mc_addr
, &sc
->sc_if
, inm
);
1646 memset(&sc
->sc_imo
, 0, sizeof(sc
->sc_imo
));
1648 if (sc
->sc_carpdev
!= NULL
&& sc
->sc_naddrs
> 0)
1649 carp_join_multicast(sc
);
1652 if (sc
->sc_naddrs
== 0 && sc
->sc_naddrs6
== 0) {
1653 sc
->sc_if
.if_flags
&= ~IFF_UP
;
1654 carp_set_state(sc
, INIT
);
1656 carp_hmac_prepare(sc
);
1663 carp_set_addr(struct carp_softc
*sc
, struct sockaddr_in
*sin
)
1665 struct ifnet
*ifp
= sc
->sc_carpdev
;
1666 struct in_ifaddr
*ia
, *ia_if
;
1669 if (sin
->sin_addr
.s_addr
== 0) {
1670 if (!(sc
->sc_if
.if_flags
& IFF_UP
))
1671 carp_set_state(sc
, INIT
);
1673 sc
->sc_if
.if_flags
|= IFF_UP
;
1678 /* we have to do this by hand to ensure we don't match on ourselves */
1680 for (ia
= TAILQ_FIRST(&in_ifaddrhead
); ia
;
1681 ia
= TAILQ_NEXT(ia
, ia_list
)) {
1683 /* and, yeah, we need a multicast-capable iface too */
1684 if (ia
->ia_ifp
!= &sc
->sc_if
&&
1685 ia
->ia_ifp
->if_type
!= IFT_CARP
&&
1686 (ia
->ia_ifp
->if_flags
& IFF_MULTICAST
) &&
1687 (sin
->sin_addr
.s_addr
& ia
->ia_subnetmask
) ==
1697 if (ifp
!= ia
->ia_ifp
)
1698 return (EADDRNOTAVAIL
);
1704 if ((error
= carp_set_ifp(sc
, ifp
)))
1707 if (sc
->sc_carpdev
== NULL
)
1708 return (EADDRNOTAVAIL
);
1710 if (sc
->sc_naddrs
== 0 && (error
= carp_join_multicast(sc
)) != 0)
1714 if (sc
->sc_carpdev
!= NULL
)
1715 sc
->sc_if
.if_flags
|= IFF_UP
;
1717 carp_set_state(sc
, INIT
);
1721 * Hook if_addrhooks so that we get a callback after in_ifinit has run,
1722 * to correct any inappropriate routes that it inserted.
1724 if (sc
->ah_cookie
== 0) {
1725 /* XXX link address hook */
1732 carp_join_multicast(struct carp_softc
*sc
)
1734 struct ip_moptions
*imo
= &sc
->sc_imo
, tmpimo
;
1735 struct in_addr addr
;
1737 memset(&tmpimo
, 0, sizeof(tmpimo
));
1738 addr
.s_addr
= INADDR_CARP_GROUP
;
1739 if ((tmpimo
.imo_membership
[0] =
1740 in_addmulti(&addr
, &sc
->sc_if
)) == NULL
) {
1744 imo
->imo_membership
[0] = tmpimo
.imo_membership
[0];
1745 imo
->imo_num_memberships
= 1;
1746 imo
->imo_multicast_ifp
= &sc
->sc_if
;
1747 imo
->imo_multicast_ttl
= CARP_DFLTTL
;
1748 imo
->imo_multicast_loop
= 0;
1755 carp_set_addr6(struct carp_softc
*sc
, struct sockaddr_in6
*sin6
)
1757 struct ifnet
*ifp
= sc
->sc_carpdev
;
1758 struct in6_ifaddr
*ia
, *ia_if
;
1761 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
)) {
1762 if (!(sc
->sc_if
.if_flags
& IFF_UP
))
1763 carp_set_state(sc
, INIT
);
1765 sc
->sc_if
.if_flags
|= IFF_UP
;
1770 /* we have to do this by hand to ensure we don't match on ourselves */
1772 for (ia
= in6_ifaddr
; ia
; ia
= ia
->ia_next
) {
1775 for (i
= 0; i
< 4; i
++) {
1776 if ((sin6
->sin6_addr
.s6_addr32
[i
] &
1777 ia
->ia_prefixmask
.sin6_addr
.s6_addr32
[i
]) !=
1778 (ia
->ia_addr
.sin6_addr
.s6_addr32
[i
] &
1779 ia
->ia_prefixmask
.sin6_addr
.s6_addr32
[i
]))
1782 /* and, yeah, we need a multicast-capable iface too */
1783 if (ia
->ia_ifp
!= &sc
->sc_if
&&
1784 ia
->ia_ifp
->if_type
!= IFT_CARP
&&
1785 (ia
->ia_ifp
->if_flags
& IFF_MULTICAST
) &&
1794 if (sc
->sc_carpdev
) {
1795 if (sc
->sc_carpdev
!= ia
->ia_ifp
)
1796 return (EADDRNOTAVAIL
);
1802 if ((error
= carp_set_ifp(sc
, ifp
)))
1805 if (sc
->sc_carpdev
== NULL
)
1806 return (EADDRNOTAVAIL
);
1808 if (sc
->sc_naddrs6
== 0 && (error
= carp_join_multicast6(sc
)) != 0)
1812 if (sc
->sc_carpdev
!= NULL
)
1813 sc
->sc_if
.if_flags
|= IFF_UP
;
1814 carp_set_state(sc
, INIT
);
1821 carp_join_multicast6(struct carp_softc
*sc
)
1823 struct in6_multi_mship
*imm
, *imm2
;
1824 struct ip6_moptions
*im6o
= &sc
->sc_im6o
;
1825 struct sockaddr_in6 addr6
;
1828 /* Join IPv6 CARP multicast group */
1829 memset(&addr6
, 0, sizeof(addr6
));
1830 addr6
.sin6_family
= AF_INET6
;
1831 addr6
.sin6_len
= sizeof(addr6
);
1832 addr6
.sin6_addr
.s6_addr16
[0] = htons(0xff02);
1833 addr6
.sin6_addr
.s6_addr16
[1] = htons(sc
->sc_if
.if_index
);
1834 addr6
.sin6_addr
.s6_addr8
[15] = 0x12;
1835 if ((imm
= in6_joingroup(&sc
->sc_if
,
1836 &addr6
.sin6_addr
, &error
, 0)) == NULL
) {
1839 /* join solicited multicast address */
1840 memset(&addr6
.sin6_addr
, 0, sizeof(addr6
.sin6_addr
));
1841 addr6
.sin6_addr
.s6_addr16
[0] = htons(0xff02);
1842 addr6
.sin6_addr
.s6_addr16
[1] = htons(sc
->sc_if
.if_index
);
1843 addr6
.sin6_addr
.s6_addr32
[1] = 0;
1844 addr6
.sin6_addr
.s6_addr32
[2] = htonl(1);
1845 addr6
.sin6_addr
.s6_addr32
[3] = 0;
1846 addr6
.sin6_addr
.s6_addr8
[12] = 0xff;
1847 if ((imm2
= in6_joingroup(&sc
->sc_if
,
1848 &addr6
.sin6_addr
, &error
, 0)) == NULL
) {
1849 in6_leavegroup(imm
);
1853 /* apply v6 multicast membership */
1854 im6o
->im6o_multicast_ifp
= &sc
->sc_if
;
1856 LIST_INSERT_HEAD(&im6o
->im6o_memberships
, imm
,
1859 LIST_INSERT_HEAD(&im6o
->im6o_memberships
, imm2
,
1868 carp_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
1870 struct lwp
*l
= curlwp
; /* XXX */
1871 struct carp_softc
*sc
= ifp
->if_softc
, *vr
;
1872 struct carpreq carpr
;
1875 struct ifnet
*cdev
= NULL
;
1878 ifa
= (struct ifaddr
*)data
;
1879 ifr
= (struct ifreq
*)data
;
1882 case SIOCINITIFADDR
:
1883 switch (ifa
->ifa_addr
->sa_family
) {
1886 sc
->sc_if
.if_flags
|= IFF_UP
;
1887 memcpy(ifa
->ifa_dstaddr
, ifa
->ifa_addr
,
1888 sizeof(struct sockaddr
));
1889 error
= carp_set_addr(sc
, satosin(ifa
->ifa_addr
));
1894 sc
->sc_if
.if_flags
|= IFF_UP
;
1895 error
= carp_set_addr6(sc
, satosin6(ifa
->ifa_addr
));
1899 error
= EAFNOSUPPORT
;
1905 if ((error
= ifioctl_common(ifp
, cmd
, data
)) != 0)
1907 if (sc
->sc_state
!= INIT
&& !(ifr
->ifr_flags
& IFF_UP
)) {
1908 callout_stop(&sc
->sc_ad_tmo
);
1909 callout_stop(&sc
->sc_md_tmo
);
1910 callout_stop(&sc
->sc_md6_tmo
);
1911 if (sc
->sc_state
== MASTER
) {
1912 /* we need the interface up to bow out */
1913 sc
->sc_if
.if_flags
|= IFF_UP
;
1917 sc
->sc_if
.if_flags
&= ~IFF_UP
;
1918 carp_set_state(sc
, INIT
);
1920 } else if (sc
->sc_state
== INIT
&& (ifr
->ifr_flags
& IFF_UP
)) {
1921 sc
->sc_if
.if_flags
|= IFF_UP
;
1929 if ((error
= kauth_authorize_network(l
->l_cred
,
1930 KAUTH_NETWORK_INTERFACE
,
1931 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV
, ifp
, (void *)cmd
,
1934 if ((error
= copyin(ifr
->ifr_data
, &carpr
, sizeof carpr
)))
1937 if (carpr
.carpr_carpdev
[0] != '\0' &&
1938 (cdev
= ifunit(carpr
.carpr_carpdev
)) == NULL
)
1940 if ((error
= carp_set_ifp(sc
, cdev
)))
1942 if (sc
->sc_state
!= INIT
&& carpr
.carpr_state
!= sc
->sc_state
) {
1943 switch (carpr
.carpr_state
) {
1945 callout_stop(&sc
->sc_ad_tmo
);
1946 carp_set_state(sc
, BACKUP
);
1948 carp_setroute(sc
, RTM_DELETE
);
1951 carp_master_down(sc
);
1957 if (carpr
.carpr_vhid
> 0) {
1958 if (carpr
.carpr_vhid
> 255) {
1962 if (sc
->sc_carpdev
) {
1963 struct carp_if
*cif
;
1964 cif
= (struct carp_if
*)sc
->sc_carpdev
->if_carp
;
1965 TAILQ_FOREACH(vr
, &cif
->vhif_vrs
, sc_list
)
1967 vr
->sc_vhid
== carpr
.carpr_vhid
)
1970 sc
->sc_vhid
= carpr
.carpr_vhid
;
1971 carp_set_enaddr(sc
);
1972 carp_set_state(sc
, INIT
);
1975 if (carpr
.carpr_advbase
> 0 || carpr
.carpr_advskew
> 0) {
1976 if (carpr
.carpr_advskew
> 254) {
1980 if (carpr
.carpr_advbase
> 255) {
1984 sc
->sc_advbase
= carpr
.carpr_advbase
;
1985 sc
->sc_advskew
= carpr
.carpr_advskew
;
1988 memcpy(sc
->sc_key
, carpr
.carpr_key
, sizeof(sc
->sc_key
));
1998 memset(&carpr
, 0, sizeof(carpr
));
1999 if (sc
->sc_carpdev
!= NULL
)
2000 strlcpy(carpr
.carpr_carpdev
, sc
->sc_carpdev
->if_xname
,
2002 carpr
.carpr_state
= sc
->sc_state
;
2003 carpr
.carpr_vhid
= sc
->sc_vhid
;
2004 carpr
.carpr_advbase
= sc
->sc_advbase
;
2005 carpr
.carpr_advskew
= sc
->sc_advskew
;
2007 if ((l
!= NULL
) && (error
= kauth_authorize_network(l
->l_cred
,
2008 KAUTH_NETWORK_INTERFACE
,
2009 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV
, ifp
, (void *)cmd
,
2011 memcpy(carpr
.carpr_key
, sc
->sc_key
,
2012 sizeof(carpr
.carpr_key
));
2013 error
= copyout(&carpr
, ifr
->ifr_data
, sizeof(carpr
));
2017 error
= carp_ether_addmulti(sc
, ifr
);
2021 error
= carp_ether_delmulti(sc
, ifr
);
2025 error
= ether_ioctl(ifp
, cmd
, data
);
2028 carp_hmac_prepare(sc
);
2034 * Start output on carp interface. This function should never be called.
2037 carp_start(struct ifnet
*ifp
)
2040 printf("%s: start called\n", ifp
->if_xname
);
2045 carp_output(struct ifnet
*ifp
, struct mbuf
*m
, const struct sockaddr
*sa
,
2048 struct carp_softc
*sc
= ((struct carp_softc
*)ifp
->if_softc
);
2050 if (sc
->sc_carpdev
!= NULL
&& sc
->sc_state
== MASTER
) {
2051 return (sc
->sc_carpdev
->if_output(ifp
, m
, sa
, rt
));
2054 return (ENETUNREACH
);
2059 carp_set_state(struct carp_softc
*sc
, int state
)
2061 static const char *carp_states
[] = { CARP_STATES
};
2062 if (sc
->sc_state
== state
)
2065 CARP_LOG(sc
, ("state transition from: %s -> to: %s", carp_states
[sc
->sc_state
], carp_states
[state
]));
2067 sc
->sc_state
= state
;
2070 sc
->sc_if
.if_link_state
= LINK_STATE_DOWN
;
2073 sc
->sc_if
.if_link_state
= LINK_STATE_UP
;
2076 sc
->sc_if
.if_link_state
= LINK_STATE_UNKNOWN
;
2079 rt_ifmsg(&sc
->sc_if
);
2083 carp_carpdev_state(void *v
)
2085 struct carp_if
*cif
;
2086 struct carp_softc
*sc
;
2087 struct ifnet
*ifp
= v
;
2089 if (ifp
->if_type
== IFT_CARP
)
2092 cif
= (struct carp_if
*)ifp
->if_carp
;
2094 TAILQ_FOREACH(sc
, &cif
->vhif_vrs
, sc_list
) {
2095 int suppressed
= sc
->sc_suppress
;
2097 if (sc
->sc_carpdev
->if_link_state
== LINK_STATE_DOWN
||
2098 !(sc
->sc_carpdev
->if_flags
& IFF_UP
)) {
2099 sc
->sc_if
.if_flags
&= ~IFF_RUNNING
;
2100 callout_stop(&sc
->sc_ad_tmo
);
2101 callout_stop(&sc
->sc_md_tmo
);
2102 callout_stop(&sc
->sc_md6_tmo
);
2103 carp_set_state(sc
, INIT
);
2104 sc
->sc_suppress
= 1;
2107 carp_suppress_preempt
++;
2108 if (carp_suppress_preempt
== 1)
2112 carp_set_state(sc
, INIT
);
2113 sc
->sc_suppress
= 0;
2116 carp_suppress_preempt
--;
2122 carp_ether_addmulti(struct carp_softc
*sc
, struct ifreq
*ifr
)
2124 const struct sockaddr
*sa
= ifreq_getaddr(SIOCADDMULTI
, ifr
);
2126 struct carp_mc_entry
*mc
;
2127 u_int8_t addrlo
[ETHER_ADDR_LEN
], addrhi
[ETHER_ADDR_LEN
];
2130 ifp
= sc
->sc_carpdev
;
2134 error
= ether_addmulti(sa
, &sc
->sc_ac
);
2135 if (error
!= ENETRESET
)
2139 * This is new multicast address. We have to tell parent
2140 * about it. Also, remember this multicast address so that
2141 * we can delete them on unconfigure.
2143 mc
= malloc(sizeof(struct carp_mc_entry
), M_DEVBUF
, M_NOWAIT
);
2150 * As ether_addmulti() returns ENETRESET, following two
2151 * statement shouldn't fail.
2153 (void)ether_multiaddr(sa
, addrlo
, addrhi
);
2154 ETHER_LOOKUP_MULTI(addrlo
, addrhi
, &sc
->sc_ac
, mc
->mc_enm
);
2155 memcpy(&mc
->mc_addr
, sa
, sa
->sa_len
);
2156 LIST_INSERT_HEAD(&sc
->carp_mc_listhead
, mc
, mc_entries
);
2158 error
= (*ifp
->if_ioctl
)(ifp
, SIOCADDMULTI
, ifr
);
2165 LIST_REMOVE(mc
, mc_entries
);
2168 (void)ether_delmulti(sa
, &sc
->sc_ac
);
2174 carp_ether_delmulti(struct carp_softc
*sc
, struct ifreq
*ifr
)
2176 const struct sockaddr
*sa
= ifreq_getaddr(SIOCDELMULTI
, ifr
);
2178 struct ether_multi
*enm
;
2179 struct carp_mc_entry
*mc
;
2180 u_int8_t addrlo
[ETHER_ADDR_LEN
], addrhi
[ETHER_ADDR_LEN
];
2183 ifp
= sc
->sc_carpdev
;
2188 * Find a key to lookup carp_mc_entry. We have to do this
2189 * before calling ether_delmulti for obvious reason.
2191 if ((error
= ether_multiaddr(sa
, addrlo
, addrhi
)) != 0)
2193 ETHER_LOOKUP_MULTI(addrlo
, addrhi
, &sc
->sc_ac
, enm
);
2197 LIST_FOREACH(mc
, &sc
->carp_mc_listhead
, mc_entries
)
2198 if (mc
->mc_enm
== enm
)
2201 /* We won't delete entries we didn't add */
2205 error
= ether_delmulti(sa
, &sc
->sc_ac
);
2206 if (error
!= ENETRESET
)
2209 /* We no longer use this multicast address. Tell parent so. */
2210 error
= (*ifp
->if_ioctl
)(ifp
, SIOCDELMULTI
, ifr
);
2212 /* And forget about this address. */
2213 LIST_REMOVE(mc
, mc_entries
);
2216 (void)ether_addmulti(sa
, &sc
->sc_ac
);
2221 * Delete any multicast address we have asked to add from parent
2222 * interface. Called when the carp is being unconfigured.
2225 carp_ether_purgemulti(struct carp_softc
*sc
)
2227 struct ifnet
*ifp
= sc
->sc_carpdev
; /* Parent. */
2228 struct carp_mc_entry
*mc
;
2232 char ifr_name
[IFNAMSIZ
];
2233 struct sockaddr_storage ifr_ss
;
2236 struct ifreq
*ifr
= &u
.ifreq
;
2241 memcpy(ifr
->ifr_name
, ifp
->if_xname
, IFNAMSIZ
);
2242 while ((mc
= LIST_FIRST(&sc
->carp_mc_listhead
)) != NULL
) {
2243 memcpy(&ifr
->ifr_addr
, &mc
->mc_addr
, mc
->mc_addr
.ss_len
);
2244 (void)(*ifp
->if_ioctl
)(ifp
, SIOCDELMULTI
, ifr
);
2245 LIST_REMOVE(mc
, mc_entries
);
2251 sysctl_net_inet_carp_stats(SYSCTLFN_ARGS
)
2254 return (NETSTAT_SYSCTL(carpstat_percpu
, CARP_NSTATS
));
2261 sysctl_net_inet_carp_setup(NULL
);
2265 sysctl_net_inet_carp_setup(struct sysctllog
**clog
)
2268 sysctl_createv(clog
, 0, NULL
, NULL
,
2270 CTLTYPE_NODE
, "net", NULL
,
2273 sysctl_createv(clog
, 0, NULL
, NULL
,
2275 CTLTYPE_NODE
, "inet", NULL
,
2277 CTL_NET
, PF_INET
, CTL_EOL
);
2278 sysctl_createv(clog
, 0, NULL
, NULL
,
2280 CTLTYPE_NODE
, "carp",
2281 SYSCTL_DESCR("CARP related settings"),
2283 CTL_NET
, PF_INET
, IPPROTO_CARP
, CTL_EOL
);
2285 sysctl_createv(clog
, 0, NULL
, NULL
,
2286 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
2287 CTLTYPE_INT
, "preempt",
2288 SYSCTL_DESCR("Enable CARP Preempt"),
2289 NULL
, 0, &carp_opts
[CARPCTL_PREEMPT
], 0,
2290 CTL_NET
, PF_INET
, IPPROTO_CARP
,
2291 CTL_CREATE
, CTL_EOL
);
2292 sysctl_createv(clog
, 0, NULL
, NULL
,
2293 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
2294 CTLTYPE_INT
, "arpbalance",
2295 SYSCTL_DESCR("Enable ARP balancing"),
2296 NULL
, 0, &carp_opts
[CARPCTL_ARPBALANCE
], 0,
2297 CTL_NET
, PF_INET
, IPPROTO_CARP
,
2298 CTL_CREATE
, CTL_EOL
);
2299 sysctl_createv(clog
, 0, NULL
, NULL
,
2300 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
2301 CTLTYPE_INT
, "allow",
2302 SYSCTL_DESCR("Enable CARP"),
2303 NULL
, 0, &carp_opts
[CARPCTL_ALLOW
], 0,
2304 CTL_NET
, PF_INET
, IPPROTO_CARP
,
2305 CTL_CREATE
, CTL_EOL
);
2306 sysctl_createv(clog
, 0, NULL
, NULL
,
2307 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
2309 SYSCTL_DESCR("CARP logging"),
2310 NULL
, 0, &carp_opts
[CARPCTL_LOG
], 0,
2311 CTL_NET
, PF_INET
, IPPROTO_CARP
,
2312 CTL_CREATE
, CTL_EOL
);
2313 sysctl_createv(clog
, 0, NULL
, NULL
,
2315 CTLTYPE_STRUCT
, "stats",
2316 SYSCTL_DESCR("CARP statistics"),
2317 sysctl_net_inet_carp_stats
, 0, NULL
, 0,
2318 CTL_NET
, PF_INET
, IPPROTO_CARP
, CARPCTL_STATS
,