Add CARP (Common Address Redundancy Protocol), which allows multiple

hosts to share an IP address, providing high availability and load
balancing.

Original work on CARP done by Michael Shalayeff, with many
additions by Marco Pfatschbacher and Ryan McBride.

FreeBSD port done solely by Max Laier.

Patch by:	mlaier
Obtained from:	OpenBSD (mickey, mcbride)
This commit is contained in:
Gleb Smirnoff 2005-02-22 13:04:05 +00:00
parent c8d07e7f11
commit a97719482d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=142215
28 changed files with 2796 additions and 12 deletions

View File

@ -119,7 +119,7 @@ ipcomp 108 IPComp # IP Payload Compression Protocol
snp 109 SNP # Sitara Networks Protocol
compaq-peer 110 Compaq-Peer # Compaq Peer Protocol
ipx-in-ip 111 IPX-in-IP # IPX in IP
vrrp 112 VRRP # Virtual Router Redundancy Protocol
carp 112 CARP vrrp # Common Address Redundancy Protocol
pgm 113 PGM # PGM Reliable Transport Protocol
# 114 # any 0-hop protocol
l2tp 115 L2TP # Layer Two Tunneling Protocol
@ -142,5 +142,6 @@ pipe 131 PIPE # Private IP Encapsulation within IP
sctp 132 SCTP # Stream Control Transmission Protocol
fc 133 FC # Fibre Channel
# 134-254 # Unassigned
pfsync 240 PFSYNC # PF Synchronization
# 255 # Reserved
divert 258 DIVERT # Divert pseudo-protocol [non IANA]

View File

@ -23,6 +23,9 @@ SRCS+= ifmedia.c # SIOC[GS]IFMEDIA support
SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
SRCS+= ifieee80211.c # SIOC[GS]IEEE80211 support
SRCS+= ifcarp.c # SIOC[GS]VH support
SRCS+= ifpfsync.c # pfsync(4) support
.if !defined(RELEASE_CRUNCH)
SRCS+= af_ipx.c # IPX support
DPADD= ${LIBIPX}

199
sbin/ifconfig/ifcarp.c Normal file
View File

@ -0,0 +1,199 @@
/* $FreeBSD$ */
/* from $OpenBSD: ifconfig.c,v 1.82 2003/10/19 05:43:35 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
* Copyright (c) 2003 Ryan McBride. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/ip_carp.h>
#include <net/route.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#include "ifconfig.h"
static const char *carp_states[] = { CARP_STATES };
void carp_status(int s, const struct rt_addrinfo *);
void setcarp_advbase(const char *,int, int, const struct afswtch *rafp);
void setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
void setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
void setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
void
carp_status(int s, const struct rt_addrinfo *info __unused)
{
const char *state;
struct carpreq carpr;
memset((char *)&carpr, 0, sizeof(struct carpreq));
ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
return;
if (carpr.carpr_vhid > 0) {
if (carpr.carpr_state > CARP_MAXSTATE)
state = "<UNKNOWN>";
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);
}
return;
}
void
setcarp_passwd(const char *val, int d, int s, const struct afswtch *afp)
{
struct carpreq carpr;
memset((char *)&carpr, 0, sizeof(struct carpreq));
ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
err(1, "SIOCGVH");
/* XXX Should hash the password into the key here, perhaps? */
strlcpy(carpr.carpr_key, val, CARP_KEY_LEN);
if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
err(1, "SIOCSVH");
return;
}
void
setcarp_vhid(const char *val, int d, int s, const struct afswtch *afp)
{
int vhid;
struct carpreq carpr;
vhid = atoi(val);
if (vhid <= 0)
errx(1, "vhid must be greater than 0");
memset((char *)&carpr, 0, sizeof(struct carpreq));
ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
err(1, "SIOCGVH");
carpr.carpr_vhid = vhid;
if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
err(1, "SIOCSVH");
return;
}
void
setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
{
int advskew;
struct carpreq carpr;
advskew = atoi(val);
memset((char *)&carpr, 0, sizeof(struct carpreq));
ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
err(1, "SIOCGVH");
carpr.carpr_advskew = advskew;
if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
err(1, "SIOCSVH");
return;
}
void
setcarp_advbase(const char *val, int d, int s, const struct afswtch *afp)
{
int advbase;
struct carpreq carpr;
advbase = atoi(val);
memset((char *)&carpr, 0, sizeof(struct carpreq));
ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
err(1, "SIOCGVH");
carpr.carpr_advbase = advbase;
if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
err(1, "SIOCSVH");
return;
}
static struct cmd carp_cmds[] = {
DEF_CMD_ARG("advbase", setcarp_advbase),
DEF_CMD_ARG("advskew", setcarp_advskew),
DEF_CMD_ARG("pass", setcarp_passwd),
DEF_CMD_ARG("vhid", setcarp_vhid),
};
static struct afswtch af_carp = {
.af_name = "af_carp",
.af_af = AF_UNSPEC,
.af_status = carp_status,
};
static __constructor void
carp_ctor(void)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
for (i = 0; i < N(carp_cmds); i++)
cmd_register(&carp_cmds[i]);
af_register(&af_carp);
#undef N
}

144
sbin/ifconfig/ifpfsync.c Normal file
View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2003 Ryan McBride. All rights reserved.
* Copyright (c) 2004 Max Laier. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/pfvar.h>
#include <net/if_pfsync.h>
#include <net/route.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ifconfig.h"
void setpfsync_syncif(const char *, int, int, const struct afswtch *rafp);
void unsetpfsync_syncif(const char *, int, int, const struct afswtch *rafp);
void setpfsync_maxupd(const char *, int, int, const struct afswtch *rafp);
void pfsync_status(int, const struct rt_addrinfo *);
void
setpfsync_syncif(const char *val, int d, int s, const struct afswtch *rafp)
{
struct pfsyncreq preq;
bzero((char *)&preq, sizeof(struct pfsyncreq));
ifr.ifr_data = (caddr_t)&preq;
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
err(1, "SIOCGETPFSYNC");
strlcpy(preq.pfsyncr_syncif, val, sizeof(preq.pfsyncr_syncif));
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
err(1, "SIOCSETPFSYNC");
}
void
unsetpfsync_syncif(const char *val, int d, int s, const struct afswtch *rafp)
{
struct pfsyncreq preq;
bzero((char *)&preq, sizeof(struct pfsyncreq));
ifr.ifr_data = (caddr_t)&preq;
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
err(1, "SIOCGETPFSYNC");
bzero((char *)&preq.pfsyncr_syncif, sizeof(preq.pfsyncr_syncif));
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
err(1, "SIOCSETPFSYNC");
}
void
setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp)
{
int maxupdates;
struct pfsyncreq preq;
maxupdates = atoi(val);
memset((char *)&preq, 0, sizeof(struct pfsyncreq));
ifr.ifr_data = (caddr_t)&preq;
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
err(1, "SIOCGETPFSYNC");
preq.pfsyncr_maxupdates = maxupdates;
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
err(1, "SIOCSETPFSYNC");
}
void
pfsync_status(int s, const struct rt_addrinfo *info __unused)
{
struct pfsyncreq preq;
bzero((char *)&preq, sizeof(struct pfsyncreq));
ifr.ifr_data = (caddr_t)&preq;
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
return;
if (preq.pfsyncr_syncif[0] != '\0') {
printf("\tpfsync: syncif: %s maxupd: %d\n",
preq.pfsyncr_syncif, preq.pfsyncr_maxupdates);
}
}
static struct cmd pfsync_cmds[] = {
DEF_CMD_ARG("syncif", setpfsync_syncif),
DEF_CMD_ARG("maxupd", setpfsync_maxupd),
DEF_CMD("-syncif", 1, unsetpfsync_syncif),
};
static struct afswtch af_pfsync = {
.af_name = "af_pfsync",
.af_af = AF_UNSPEC,
.af_status = pfsync_status,
};
static __constructor void
pfsync_ctor(void)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
for (i = 0; i < N(pfsync_cmds); i++)
cmd_register(&pfsync_cmds[i]);
af_register(&af_pfsync);
#undef N
}

View File

@ -279,6 +279,7 @@ crypto/rijndael/rijndael-api-fst.c optional geom_bde
crypto/rijndael/rijndael-api-fst.c optional random
crypto/rijndael/rijndael-api.c optional ipsec
crypto/rijndael/rijndael-api.c optional wlan_ccmp
crypto/sha1.c optional carp
crypto/sha1.c optional netgraph_mppc_encryption
crypto/sha1.c optional crypto
crypto/sha1.c optional ipsec
@ -1483,6 +1484,7 @@ netinet/if_atm.c optional atm
netinet/if_ether.c optional ether
netinet/igmp.c optional inet
netinet/in.c optional inet
netinet/ip_carp.c optional carp
netinet/in_gif.c optional gif inet
netinet/ip_gre.c optional gre inet
netinet/ip_id.c optional inet

View File

@ -610,6 +610,7 @@ NDEVFSOVERFLOW opt_devfs.h
DEV_BPF opt_bpf.h
DEV_ISA opt_isa.h
DEV_MCA opt_mca.h
DEV_CARP opt_carp.h
DEV_SPLASH opt_splash.h
EISA_SLOTS opt_eisa.h

View File

@ -34,6 +34,7 @@
#include "opt_inet6.h"
#include "opt_inet.h"
#include "opt_mac.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/types.h>
@ -78,6 +79,9 @@
#ifdef INET
#include <netinet/if_ether.h>
#endif
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
@ -529,6 +533,12 @@ if_detach(struct ifnet *ifp)
int found;
EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
#ifdef DEV_CARP
/* Maybe hook to the generalized departure handler above?!? */
if (ifp->if_carp)
carp_ifdetach(ifp);
#endif
/*
* Remove routes and flush queues.
*/
@ -933,6 +943,10 @@ if_unroute(struct ifnet *ifp, int flag, int fam)
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
if_qflush(&ifp->if_snd);
#ifdef DEV_CARP
if (ifp->if_carp)
carp_carpdev_state(ifp->if_carp);
#endif
rt_ifmsg(ifp);
}
@ -951,6 +965,10 @@ if_route(struct ifnet *ifp, int flag, int fam)
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
pfctlinput(PRC_IFUP, ifa->ifa_addr);
#ifdef DEV_CARP
if (ifp->if_carp)
carp_carpdev_state(ifp->if_carp);
#endif
rt_ifmsg(ifp);
#ifdef INET6
in6_if_up(ifp);

View File

@ -37,6 +37,7 @@
#include "opt_bdg.h"
#include "opt_mac.h"
#include "opt_netgraph.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -73,6 +74,10 @@
#include <netinet6/nd6.h>
#endif
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
#ifdef IPX
#include <netipx/ipx.h>
#include <netipx/ipx_if.h>
@ -315,6 +320,12 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
}
}
#ifdef DEV_CARP
if (ifp->if_carp &&
(error = carp_output(ifp, m, dst, NULL)))
goto bad;
#endif
/* Handle ng_ether(4) processing, if any */
if (IFP2AC(ifp)->ac_netgraph != NULL) {
if ((error = (*ng_ether_output_p)(ifp, &m)) != 0) {
@ -606,6 +617,18 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
if (!(BDG_ACTIVE(ifp)) &&
!((ether_type == ETHERTYPE_VLAN || m->m_flags & M_VLANTAG) &&
ifp->if_nvlans > 0)) {
#ifdef DEV_CARP
/*
* XXX: Okay, we need to call carp_forus() and - if it is for us
* jump over code that does the normal check
* "ac_enaddr == ether_dhost". The check sequence is a bit
* different from OpenBSD, so we jump over as few code as possible,
* to catch _all_ sanity checks. This needs evaluation, to see if
* the carp ether_dhost values break any of these checks!
*/
if (ifp->if_carp && carp_forus(ifp->if_carp, eh->ether_dhost))
goto pre_stats;
#endif
/*
* Discard packet if upper layers shouldn't see it because it
* was unicast to a different Ethernet address. If the driver
@ -628,6 +651,9 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
}
}
#ifdef DEV_CARP
pre_stats:
#endif
/* Discard packet if interface is not up */
if ((ifp->if_flags & IFF_UP) == 0) {
m_freem(m);

View File

@ -226,6 +226,11 @@ int ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr,
#define IFM_ATM_NOSCRAMB 0x00000200 /* no scrambling */
#define IFM_ATM_UNASSIGNED 0x00000400 /* unassigned cells */
/*
* CARP Common Address Redundancy Protocol
*/
#define IFM_CARP 0x000000c0
/*
* Shared media sub-types
*/
@ -299,6 +304,7 @@ struct ifmedia_description {
{ IFM_FDDI, "FDDI" }, \
{ IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \
{ IFM_ATM, "ATM" }, \
{ IFM_CARP, "Common Address Redundancy Protocol" }, \
{ 0, NULL }, \
}

View File

@ -247,4 +247,5 @@
#define IFT_FAITH 0xf2
#define IFT_PFLOG 0xf6
#define IFT_PFSYNC 0xf7
#define IFT_CARP 0xf8 /* Common Address Redundancy Protocol */
#endif /* !_NET_IF_TYPES_H_ */

View File

@ -68,6 +68,7 @@ struct rtentry;
struct rt_addrinfo;
struct socket;
struct ether_header;
struct carp_if;
#endif
#include <sys/queue.h> /* get TAILQ macros */
@ -146,7 +147,7 @@ struct ifnet {
*/
struct knlist if_klist; /* events attached to this if */
int if_pcount; /* number of promiscuous listeners */
void *if_carp; /* carp (tbd) interface pointer */
struct carp_if *if_carp; /* carp interface structure */
struct bpf_if *if_bpf; /* packet filter structure */
u_short if_index; /* numeric abbreviation for this if */
short if_timer; /* time 'til if_watchdog called */

View File

@ -39,6 +39,7 @@
#include "opt_inet.h"
#include "opt_bdg.h"
#include "opt_mac.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/kernel.h>
@ -67,6 +68,10 @@
#include <net/if_arc.h>
#include <net/iso88025.h>
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
#define SIN(s) ((struct sockaddr_in *)s)
#define SDL(s) ((struct sockaddr_dl *)s)
@ -545,6 +550,7 @@ in_arpinput(m)
struct sockaddr_dl *sdl;
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
u_int8_t *enaddr = NULL;
int op, rif_len;
int req_len;
@ -563,10 +569,18 @@ in_arpinput(m)
* For a bridge, we want to check the address irrespective
* of the receive interface. (This will change slightly
* when we have clusters of interfaces).
* If the interface does not match, but the recieving interface
* is part of carp, we call carp_iamatch to see if this is a
* request for the virtual host ip.
* XXX: This is really ugly!
*/
LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash)
if ((do_bridge || (ia->ia_ifp == ifp)) &&
itaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
if ((do_bridge || (ia->ia_ifp == ifp)
#ifdef DEV_CARP
|| (ifp->if_carp
&& carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr))
#endif
) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
goto match;
LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash)
if ((do_bridge || (ia->ia_ifp == ifp)) &&
@ -587,8 +601,10 @@ in_arpinput(m)
if (!do_bridge || (ia = TAILQ_FIRST(&in_ifaddrhead)) == NULL)
goto drop;
match:
if (!enaddr)
enaddr = (u_int8_t *)IF_LLADDR(ifp);
myaddr = ia->ia_addr.sin_addr;
if (!bcmp(ar_sha(ah), IF_LLADDR(ifp), ifp->if_addrlen))
if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen))
goto drop; /* it's from me, ignore it. */
if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) {
log(LOG_ERR,
@ -711,7 +727,7 @@ in_arpinput(m)
if (itaddr.s_addr == myaddr.s_addr) {
/* I am the target */
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
(void)memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln);
(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
} else {
la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
if (la == NULL) {
@ -738,7 +754,7 @@ in_arpinput(m)
goto drop;
}
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
(void)memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln);
(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
rtfree(rt);
/*
@ -880,6 +896,19 @@ arp_ifinit(ifp, ifa)
ifa->ifa_flags |= RTF_CLONING;
}
void
arp_ifinit2(ifp, ifa, enaddr)
struct ifnet *ifp;
struct ifaddr *ifa;
u_char *enaddr;
{
if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY)
arprequest(ifp, &IA_SIN(ifa)->sin_addr,
&IA_SIN(ifa)->sin_addr, enaddr);
ifa->ifa_rtrequest = arp_rtrequest;
ifa->ifa_flags |= RTF_CLONING;
}
static void
arp_init(void)
{

View File

@ -112,6 +112,7 @@ extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN];
int arpresolve(struct ifnet *ifp, struct rtentry *rt,
struct mbuf *m, struct sockaddr *dst, u_char *desten);
void arp_ifinit(struct ifnet *, struct ifaddr *);
void arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *);
#endif
#endif

View File

@ -230,6 +230,7 @@ __END_DECLS
#define IPPROTO_IPCOMP 108 /* payload compression (IPComp) */
/* 101-254: Partly Unassigned */
#define IPPROTO_PIM 103 /* Protocol Independent Mcast */
#define IPPROTO_CARP 112 /* CARP */
#define IPPROTO_PGM 113 /* PGM */
#define IPPROTO_PFSYNC 240 /* PFSYNC */
/* 255: Reserved */
@ -357,6 +358,7 @@ __END_DECLS
#define INADDR_UNSPEC_GROUP (u_int32_t)0xe0000000 /* 224.0.0.0 */
#define INADDR_ALLHOSTS_GROUP (u_int32_t)0xe0000001 /* 224.0.0.1 */
#define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */
#define INADDR_CARP_GROUP (u_int32_t)0xe0000012 /* 224.0.0.18 */
#define INADDR_PFSYNC_GROUP (u_int32_t)0xe00000f0 /* 224.0.0.240 */
#define INADDR_ALLMDNS_GROUP (u_int32_t)0xe00000fb /* 224.0.0.251 */
#define INADDR_MAX_LOCAL_GROUP (u_int32_t)0xe00000ff /* 224.0.0.255 */

View File

@ -35,6 +35,7 @@
#include "opt_ipsec.h"
#include "opt_inet6.h"
#include "opt_pf.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -90,6 +91,10 @@
#include <net/if_pfsync.h>
#endif
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
extern struct domain inetdomain;
/* Spacer for loadable protocols. */
@ -237,6 +242,14 @@ struct protosw inetsw[] = {
&rip_usrreqs
},
#endif /* DEV_PFSYNC */
#ifdef DEV_CARP
{ SOCK_RAW, &inetdomain, IPPROTO_CARP, PR_ATOMIC|PR_ADDR,
carp_input, (pr_output_t*)rip_output, 0, rip_ctloutput,
0,
0, 0, 0, 0,
&rip_usrreqs
},
#endif /* DEV_CARP */
/* Spacer n-times for loadable protocols. */
IPPROTOSPACER,
IPPROTOSPACER,
@ -290,3 +303,6 @@ SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, CTLFLAG_RW, 0, "RAW");
#ifdef PIM
SYSCTL_NODE(_net_inet, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
#endif
#ifdef DEV_CARP
SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP");
#endif

2032
sys/netinet/ip_carp.c Normal file

File diff suppressed because it is too large Load Diff

163
sys/netinet/ip_carp.h Normal file
View File

@ -0,0 +1,163 @@
/* $FreeBSD$ */
/* $OpenBSD: ip_carp.h,v 1.8 2004/07/29 22:12:15 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
* Copyright (c) 2003 Ryan McBride. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _IP_CARP_H
#define _IP_CARP_H
/*
* The CARP header layout is as follows:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |Version| Type | VirtualHostID | AdvSkew | Auth Len |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | AdvBase | Checksum |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Counter (1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Counter (2) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SHA-1 HMAC (1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SHA-1 HMAC (2) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SHA-1 HMAC (3) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SHA-1 HMAC (4) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SHA-1 HMAC (5) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
struct carp_header {
#if BYTE_ORDER == LITTLE_ENDIAN
u_int8_t carp_type:4,
carp_version:4;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t carp_version:4,
carp_type:4;
#endif
u_int8_t carp_vhid; /* virtual host id */
u_int8_t carp_advskew; /* advertisement skew */
u_int8_t carp_authlen; /* size of counter+md, 32bit chunks */
u_int8_t carp_pad1; /* reserved */
u_int8_t carp_advbase; /* advertisement interval */
u_int16_t carp_cksum;
u_int32_t carp_counter[2];
unsigned char carp_md[20]; /* SHA1 HMAC */
} __packed;
#define CARP_DFLTTL 255
/* carp_version */
#define CARP_VERSION 2
/* carp_type */
#define CARP_ADVERTISEMENT 0x01
#define CARP_KEY_LEN 20 /* a sha1 hash of a passphrase */
/* carp_advbase */
#define CARP_DFLTINTV 1
/*
* Statistics.
*/
struct carpstats {
uint64_t carps_ipackets; /* total input packets, IPv4 */
uint64_t carps_ipackets6; /* total input packets, IPv6 */
uint64_t carps_badif; /* wrong interface */
uint64_t carps_badttl; /* TTL is not CARP_DFLTTL */
uint64_t carps_hdrops; /* packets shorter than hdr */
uint64_t carps_badsum; /* bad checksum */
uint64_t carps_badver; /* bad (incl unsupp) version */
uint64_t carps_badlen; /* data length does not match */
uint64_t carps_badauth; /* bad authentication */
uint64_t carps_badvhid; /* bad VHID */
uint64_t carps_badaddrs; /* bad address list */
uint64_t carps_opackets; /* total output packets, IPv4 */
uint64_t carps_opackets6; /* total output packets, IPv6 */
uint64_t carps_onomem; /* no memory for an mbuf */
uint64_t carps_ostates; /* total state updates sent */
uint64_t carps_preempt; /* if enabled, preemptions */
};
/*
* Configuration structure for SIOCSVH SIOCGVH
*/
struct carpreq {
int carpr_state;
#define CARP_STATES "INIT", "BACKUP", "MASTER"
#define CARP_MAXSTATE 2
int carpr_vhid;
int carpr_advskew;
int carpr_advbase;
unsigned char carpr_key[CARP_KEY_LEN];
};
#define SIOCSVH _IOWR('i', 245, struct ifreq)
#define SIOCGVH _IOWR('i', 246, struct ifreq)
/*
* Names for CARP sysctl objects
*/
#define CARPCTL_ALLOW 1 /* accept incoming CARP packets */
#define CARPCTL_PREEMPT 2 /* high-pri backup preemption mode */
#define CARPCTL_LOG 3 /* log bad packets */
#define CARPCTL_STATS 4 /* statistics (read-only) */
#define CARPCTL_ARPBALANCE 5 /* balance arp responses */
#define CARPCTL_MAXID 6
#define CARPCTL_NAMES { \
{ 0, 0 }, \
{ "allow", CTLTYPE_INT }, \
{ "preempt", CTLTYPE_INT }, \
{ "log", CTLTYPE_INT }, \
{ "stats", CTLTYPE_STRUCT }, \
{ "arpbalance", CTLTYPE_INT }, \
}
#ifdef _KERNEL
void carp_ifdetach (struct ifnet *);
void carp_carpdev_state(void *);
void carp_input (struct mbuf *, int);
int carp6_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 *,
u_int8_t **);
struct ifaddr *carp_iamatch6(void *, struct in6_addr *);
void *carp_macmatch6(void *, struct mbuf *, const struct in6_addr *);
struct ifnet *carp_forus (void *, void *);
#endif
#endif /* _IP_CARP_H */

View File

@ -35,6 +35,7 @@
#include "opt_ipstealth.h"
#include "opt_ipsec.h"
#include "opt_mac.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -66,6 +67,9 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <machine/in_cksum.h>
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
#include <sys/socketvar.h>
@ -509,10 +513,17 @@ ip_input(struct mbuf *m)
* XXX - Checking is incompatible with IP aliases added
* to the loopback interface instead of the interface where
* the packets are received.
*
* XXX - This is the case for carp vhost IPs as well so we
* insert a workaround. If the packet got here, we already
* checked with carp_iamatch() and carp_forus().
*/
checkif = ip_checkinterface && (ipforwarding == 0) &&
m->m_pkthdr.rcvif != NULL &&
((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
#ifdef DEV_CARP
!m->m_pkthdr.rcvif->if_carp &&
#endif
(dchg == 0);
/*

View File

@ -206,7 +206,7 @@ in6_ifloop_request(int cmd, struct ifaddr *ifa)
* rely on the cloning mechanism from the corresponding interface route
* any more.
*/
static void
void
in6_ifaddloop(struct ifaddr *ifa)
{
struct rtentry *rt;
@ -226,7 +226,7 @@ in6_ifaddloop(struct ifaddr *ifa)
* Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
* if it exists.
*/
static void
void
in6_ifremloop(struct ifaddr *ifa)
{
struct in6_ifaddr *ia;
@ -1551,6 +1551,39 @@ in6_ifinit(ifp, ia, sin6, newhost)
return (error);
}
struct in6_multi_mship *
in6_joingroup(ifp, addr, errorp)
struct ifnet *ifp;
struct in6_addr *addr;
int *errorp;
{
struct in6_multi_mship *imm;
imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT);
if (!imm) {
*errorp = ENOBUFS;
return NULL;
}
imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp);
if (!imm->i6mm_maddr) {
/* *errorp is alrady set */
free(imm, M_IPMADDR);
return NULL;
}
return imm;
}
int
in6_leavegroup(imm)
struct in6_multi_mship *imm;
{
if (imm->i6mm_maddr)
in6_delmulti(imm->i6mm_maddr);
free(imm, M_IPMADDR);
return 0;
}
/*
* Find an IPv6 interface link-local address specific to an interface.
*/

View File

@ -671,6 +671,7 @@ in6_ifattach(ifp, altifp)
#endif
case IFT_PFLOG:
case IFT_PFSYNC:
case IFT_CARP:
return;
}

View File

@ -64,6 +64,7 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/socket.h>
@ -121,6 +122,10 @@
#endif
#endif /* IPSEC */
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
#ifdef FAST_IPSEC
#include <netipsec/ipsec6.h>
#define IPSEC
@ -241,6 +246,14 @@ struct ip6protosw inet6sw[] = {
0, 0, 0, 0,
&rip6_usrreqs
},
#ifdef DEV_CARP
{ SOCK_RAW, &inet6domain, IPPROTO_CARP, PR_ATOMIC|PR_ADDR,
carp6_input, rip6_output, 0, rip6_ctloutput,
0,
0, 0, 0, 0,
&rip6_usrreqs
},
#endif /* DEV_CARP */
/* raw wildcard */
{ SOCK_RAW, &inet6domain, 0, PR_ATOMIC|PR_ADDR,
rip6_input, rip6_output, 0, rip6_ctloutput,

View File

@ -578,6 +578,8 @@ do { \
struct in6_multi *in6_addmulti __P((struct in6_addr *, struct ifnet *,
int *));
void in6_delmulti __P((struct in6_multi *));
struct in6_multi_mship *in6_joingroup(struct ifnet *, struct in6_addr *, int *);
int in6_leavegroup(struct in6_multi_mship *);
int in6_mask2len __P((struct in6_addr *, u_char *));
int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *,
struct thread *));
@ -604,6 +606,8 @@ int in6_prefix_ioctl __P((struct socket *, u_long, caddr_t,
int in6_prefix_add_ifid __P((int, struct in6_ifaddr *));
void in6_prefix_remove_ifid __P((int, struct in6_ifaddr *));
void in6_purgeprefix __P((struct ifnet *));
void in6_ifremloop(struct ifaddr *);
void in6_ifaddloop(struct ifaddr *);
int in6_is_addr_deprecated __P((struct sockaddr_in6 *));
struct inpcb;

View File

@ -2024,6 +2024,9 @@ nd6_need_cache(ifp)
#endif
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
#ifdef IFT_CARP
case IFT_CARP:
#endif
case IFT_GIF: /* XXX need more cases? */
return (1);

View File

@ -32,6 +32,8 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -59,6 +61,10 @@
#include <netinet6/nd6.h>
#include <netinet/icmp6.h>
#ifdef DEV_CARP
#include <netinet/ip_carp.h>
#endif
#include <net/net_osdep.h>
#define SDL(s) ((struct sockaddr_dl *)s)
@ -94,7 +100,7 @@ nd6_ns_input(m, off, icmp6len)
struct in6_addr taddr6;
struct in6_addr myaddr6;
char *lladdr = NULL;
struct ifaddr *ifa;
struct ifaddr *ifa = NULL;
int lladdrlen = 0;
int anycast = 0, proxy = 0, tentative = 0;
int tlladdr;
@ -193,7 +199,14 @@ nd6_ns_input(m, off, icmp6len)
* (3) "tentative" address on which DAD is being performed.
*/
/* (1) and (3) check. */
#ifdef DEV_CARP
if (ifp->if_carp)
ifa = carp_iamatch6(ifp->if_carp, &taddr6);
if (!ifa)
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
#else
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
#endif
/* (2) check. */
if (!ifa) {
@ -888,9 +901,16 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
* lladdr in sdl0. If we are not proxying (sending NA for
* my address) use lladdr configured for the interface.
*/
if (sdl0 == NULL)
if (sdl0 == NULL) {
#ifdef DEV_CARP
if (ifp->if_carp)
mac = carp_macmatch6(ifp->if_carp, m, taddr6);
if (mac == NULL)
mac = nd6_ifptomac(ifp);
#else
mac = nd6_ifptomac(ifp);
else if (sdl0->sa_family == AF_LINK) {
#endif
} else if (sdl0->sa_family == AF_LINK) {
struct sockaddr_dl *sdl;
sdl = (struct sockaddr_dl *)sdl0;
if (sdl->sdl_alen == ifp->if_addrlen)
@ -942,6 +962,9 @@ nd6_ifptomac(ifp)
#endif
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
#ifdef IFT_CARP
case IFT_CARP:
#endif
case IFT_ISO88025:
return ((caddr_t)(ifp + 1));

View File

@ -664,6 +664,7 @@ struct mbuf *m_uiotombuf(struct uio *, int, int);
#define PACKET_TAG_RTSOCKFAM 25 /* rtsock sa family */
#define PACKET_TAG_PF_TRANSLATE_LOCALHOST 26 /* PF translate localhost */
#define PACKET_TAG_IPOPTIONS 27 /* Saved IP options */
#define PACKET_TAG_CARP 28 /* CARP info */
/* Packet tag routines. */
struct m_tag *m_tag_alloc(u_int32_t, int, int, int);

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_carp.h>
#ifdef INET6
#include <netinet/ip6.h>
#endif /* INET6 */
@ -525,6 +526,50 @@ udp_stats(u_long off __unused, const char *name, int af1 __unused)
#undef p1a
}
/*
* Dump CARP statistics structure.
*/
void
carp_stats(u_long off, const char *name, int af1 __unused)
{
struct carpstats carpstat, zerostat;
size_t len = sizeof(struct carpstats);
if (zflag)
memset(&zerostat, 0, len);
if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
warn("sysctl: net.inet.carp.stats");
return;
}
printf("%s:\n", name);
#define p(f, m) if (carpstat.f || sflag <= 1) \
printf(m, (unsigned long long)carpstat.f, plural((int)carpstat.f))
#define p2(f, m) if (carpstat.f || sflag <= 1) \
printf(m, (unsigned long long)carpstat.f)
p(carps_ipackets, "\t%llu packet%s received (IPv4)\n");
p(carps_ipackets6, "\t%llu packet%s received (IPv6)\n");
p(carps_badttl, "\t\t%llu packet%s discarded for wrong TTL\n");
p(carps_hdrops, "\t\t%llu packet%s shorter than header\n");
p(carps_badsum, "\t\t%llu discarded for bad checksum%s\n");
p(carps_badver, "\t\t%llu discarded packet%s with a bad version\n");
p2(carps_badlen, "\t\t%llu discarded because packet too short\n");
p2(carps_badauth, "\t\t%llu discarded for bad authentication\n");
p2(carps_badvhid, "\t\t%llu discarded for bad vhid\n");
p2(carps_badaddrs, "\t\t%llu discarded because of a bad address list\n");
p(carps_opackets, "\t%llu packet%s sent (IPv4)\n");
p(carps_opackets6, "\t%llu packet%s sent (IPv6)\n");
p2(carps_onomem, "\t\t%llu send failed due to mbuf memory error\n");
#if notyet
p(carps_ostates, "\t\t%s state update%s sent\n");
#endif
#undef p
#undef p2
}
/*
* Dump IP statistics structure.
*/

View File

@ -136,6 +136,8 @@ static struct nlist nl[] = {
{ "_mbuf_lowm" },
#define N_CLLO 32
{ "_clust_lowm" },
#define N_CARPSTAT 33
{ "_carpstats" },
{ "" },
};
@ -171,6 +173,8 @@ struct protox {
bdg_stats, NULL, "bdg", 1 /* bridging... */ },
{ -1, -1, 1, protopr,
pim_stats, NULL, "pim", IPPROTO_PIM },
{ -1, N_CARPSTAT, 1, 0,
carp_stats, NULL, "carp", 0},
{ -1, -1, 0, NULL,
NULL, NULL, NULL, 0 }
};

View File

@ -71,6 +71,7 @@ void ip_stats(u_long, const char *, int);
void icmp_stats(u_long, const char *, int);
void igmp_stats(u_long, const char *, int);
void pim_stats(u_long, const char *, int);
void carp_stats (u_long, const char *, int);
#ifdef IPSEC
void ipsec_stats(u_long, const char *, int);
#endif