Project

General

Profile

Bug #664 » carp-20070811BR01.patch

baptiste.ritter, 08/11/2007 07:38 PM

View differences:

etc/protocols
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
sbin/ifconfig/Makefile
SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
SRCS+= ifieee80211.c # SIOC[GS]IEEE80211 support
#SRCS+= ifcarp.c # SIOC[GS]VH support
SRCS+= ifcarp.c # SIOC[GS]VH support
#SRCS+= ifpfsync.c # pfsync(4) support
SRCS+= ifbridge.c # bridge support
sbin/ifconfig/ifcarp.c
/* $Id$ */
/* from $FreeBSD: src/sbin/ifconfig/ifcarp.c,v 1.2 2005/02/22 14:07:47 glebius Exp $ */
/* 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);
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 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_other_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
}
sbin/ifconfig/ifconfig.8
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.124 2006/10/10 09:44:08 ru Exp $
.\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.19 2007/04/09 21:20:37 swildner Exp $
.\"
.Dd November 19, 2006
.Dd April 8, 2007
.Dt IFCONFIG 8
.Os
.Sh NAME
......
argument is useless and hence deprecated.
.El
.Pp
The following parameters are specific to
.Xr carp 4
interfaces:
.Bl -tag -width indent
.It Cm advbase Ar seconds
Specifies the base of the advertisement interval in seconds.
The acceptable values are 1 to 255.
The default value is 1.
.\" The default value is
.\" .Dv CARP_DFLTINTV .
.It Cm advskew Ar interval
Specifies the skew to add to the base advertisement interval to
make one host advertise slower than another host.
It is specified in 1/256 of seconds.
The acceptable values are 1 to 254.
The default value is 0.
.It Cm pass Ar phrase
Set the authentication key to
.Ar phrase .
.It Cm vhid Ar n
Set the virtual host ID.
This is a required setting.
Acceptable values are 1 to 255.
.El
.Pp
The
.Nm
utility displays the current configuration for a network interface
......
tried to alter an interface's configuration.
.Sh SEE ALSO
.Xr netstat 1 ,
.Xr carp 4 ,
.Xr ifmedia 4 ,
.Xr netintro 4 ,
.Xr polling 4 ,
sbin/ifconfig/ifmedia.c
else
printf("no carrier");
break;
case IFM_CARP:
if (ifmr.ifm_status & IFM_ACTIVE)
printf("master");
else
printf("backup");
break;
}
putchar('\n');
}
share/man/man4/Makefile
bridge.4 \
bt.4 \
cardbus.4 \
carp.4 \
ccd.4 \
cd.4 \
ch.4 \
share/man/man4/carp.4
.\" $OpenBSD: carp.4,v 1.16 2004/12/07 23:41:35 jmc Exp $
.\" $FreeBSD: src/share/man/man4/carp.4,v 1.10 2006/06/07 10:26:51 glebius Exp $
.\" $Id$
.\"
.\" 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 PROJECT 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 PROJECT 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.
.\"
.\"
.Dd April 9, 2007
.Dt CARP 4
.Os
.Sh NAME
.Nm carp
.Nd Common Address Redundancy Protocol
.Sh SYNOPSIS
.Cd "pseudo-device carp"
.Sh DESCRIPTION
The
.Nm
interface is a pseudo-device that implements and controls the
CARP protocol.
CARP allows multiple hosts on the same local network to share a set of IP addresses.
Its primary purpose is to ensure that these
addresses are always available, but in some configurations
.Nm
can also provide load balancing functionality.
.Pp
A
.Nm
interface can be created at runtime using the
.Nm ifconfig Li carp Ns Ar N Cm create
command or by configuring
it via
.Va cloned_interfaces
in the
.Pa /etc/rc.conf
file.
.Pp
To use
.Nm ,
the administrator needs to configure at minimum a common virtual host ID (VHID)
and virtual host IP address on each machine which is to take part in the virtual
group.
Additional parameters can also be set on a per-interface basis:
.Cm advbase
and
.Cm advskew ,
which are used to control how frequently the host sends advertisements when it
is the master for a virtual host, and
.Cm pass
which is used to authenticate
.Nm
advertisements.
The
.Cm advbase
parameter stands for
.Dq "advertisement base" .
It is measured in seconds and specifies the base of the advertisement interval.
The
.Cm advskew
parameter stands for
.Dq "advertisement skew" .
It is measured in 1/256 of seconds.
It is added to the base advertisement interval to make one host advertise
a bit slower that the other does.
Both
.Cm advbase
and
.Cm advskew
are put inside CARP advertisements.
These configurations can be done using
.Xr ifconfig 8 ,
or through the
.Dv SIOCSVH
.Xr ioctl 2 .
.Pp
Additionally, there are a number of global parameters which can be set using
.Xr sysctl 8 :
.Bl -tag -width ".Va net.inet.carp.arpbalance"
.It Va net.inet.carp.allow
Accept incoming
.Nm
packets.
Enabled by default.
.It Va net.inet.carp.preempt
Allow virtual hosts to preempt each other.
It is also used to failover
.Nm
interfaces as a group.
When the option is enabled and one of the
.Nm
enabled physical interfaces
goes down,
.Cm advskew
is changed to 240 on all
.Nm
interfaces.
See also the first example.
Disabled by default.
.It Va net.inet.carp.log
Value of 0 disables any logging.
Value of 1 enables logging of bad
.Nm
packets.
Values above 1 enable logging state changes of
.Nm
interfaces.
Default value is 1.
.It Va net.inet.carp.arpbalance
Balance local traffic using ARP (see below).
Disabled by default.
.It Va net.inet.carp.suppress_preempt
A read only value showing the status of preemption suppression.
Preemption can be suppressed if link on an interface is down
or when
.Xr pfsync 4
interface is not synchronized.
Value of 0 means that preemption is not suppressed, since no
problems are detected.
Every problem increments suppression counter.
.El
.Sh ARP level load balancing
The
.Nm
has limited abilities for load balancing the incoming connections
between hosts in Ethernet network.
For load balancing operation, one needs several CARP interfaces that
are configured to the same IP address, but to a different VHIDs.
Once an ARP request is received, the CARP protocol will use a hashing
function against the source IP address in the ARP request to determine
which VHID should this request belong to.
If the corresponding CARP interface is in master state, the ARP request
will be replied, otherwise it will be ignored.
See the
.Sx EXAMPLES
section for a practical example of load balancing.
.Pp
The ARP load balancing has some limitations.
First, ARP balancing only works on the local network segment.
It cannot balance traffic that crosses a router, because the
router itself will always be balanced to the same virtual host.
Second, ARP load balancing can lead to asymmetric routing
of incoming and outgoing traffic, and thus combining it with
.Xr pfsync 4
is dangerous, because this creates a race condition between
balanced routers and a host they are serving.
Imagine an incoming packet creating state on the first router, being
forwarded to its destination, and destination replying faster
than the state information is packed and synced with the second router.
If the reply would be load balanced to second router, it will be
dropped due to no state.
.Sh EXAMPLES
For firewalls and routers with multiple interfaces, it is desirable to
failover all of the
.Nm
interfaces together, when one of the physical interfaces goes down.
This is achieved by the preempt option.
Enable it on both host A and B:
.Pp
.Dl sysctl net.inet.carp.preempt=1
.Pp
Assume that host A is the preferred master and 192.168.1.x/24 is
configured on one physical interface and 192.168.2.y/24 on another.
This is the setup for host A:
.Bd -literal -offset indent
ifconfig carp0 create
ifconfig carp0 vhid 1 pass mekmitasdigoat 192.168.1.1/24
ifconfig carp1 create
ifconfig carp1 vhid 2 pass mekmitasdigoat 192.168.2.1/24
.Ed
.Pp
The setup for host B is identical, but it has a higher
.Cm advskew :
.Bd -literal -offset indent
ifconfig carp0 create
ifconfig carp0 vhid 1 advskew 100 pass mekmitasdigoat 192.168.1.1/24
ifconfig carp1 create
ifconfig carp1 vhid 2 advskew 100 pass mekmitasdigoat 192.168.2.1/24
.Ed
.Pp
Because of the preempt option, when one of the physical interfaces of
host A fails,
.Cm advskew
is adjusted to 240 on all its
.Nm
interfaces.
This will cause host B to preempt on both interfaces instead of
just the failed one.
.Pp
In order to set up an ARP balanced virtual host, it is necessary to configure
one virtual host for each physical host which would respond to ARP requests
and thus handle the traffic.
In the following example, two virtual hosts are configured on two hosts to
provide balancing and failover for the IP address 192.168.1.10.
.Pp
First the
.Nm
interfaces on host A are configured.
The
.Cm advskew
of 100 on the second virtual host means that its advertisements will be sent
out slightly less frequently.
.Bd -literal -offset indent
ifconfig carp0 create
ifconfig carp0 vhid 1 pass mekmitasdigoat 192.168.1.10/24
ifconfig carp1 create
ifconfig carp1 vhid 2 advskew 100 pass mekmitasdigoat 192.168.1.10/24
.Ed
.Pp
The configuration for host B is identical, except the
.Cm advskew
is on virtual host 1 rather than virtual host 2.
.Bd -literal -offset indent
ifconfig carp0 create
ifconfig carp0 vhid 1 advskew 100 pass mekmitasdigoat 192.168.1.10/24
ifconfig carp1 create
ifconfig carp1 vhid 2 pass mekmitasdigoat 192.168.1.10/24
.Ed
.Pp
Finally, the ARP balancing feature must be enabled on both hosts:
.Pp
.Dl sysctl net.inet.carp.arpbalance=1
.Pp
When the hosts receive an ARP request for 192.168.1.10, the source IP address
of the request is used to compute which virtual host should answer the request.
The host which is master of the selected virtual host will reply to the
request, the other(s) will ignore it.
.Pp
This way, locally connected systems will receive different ARP replies and
subsequent IP traffic will be balanced among the hosts.
If one of the hosts fails, the other will take over the virtual MAC address,
and begin answering ARP requests on its behalf.
.Sh SEE ALSO
.Xr inet 4 ,
.Xr pfsync 4 ,
.Xr rc.conf 5 ,
.Xr ifconfig 8 ,
.Xr sysctl 8
.Sh HISTORY
The
.Nm
device first appeared in
.Ox 3.5 .
share/man/man4/pfsync.4
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd November 29, 2002
.Dd April 9, 2007
.Dt PFSYNC 4
.Os
.Sh NAME
......
# ifconfig pfsync0 up syncif fxp0 maxupd 64
# tcpdump -s1500 -evtni pfsync0
.Ed
.Sh USING PFSYNC WITH CARP
.Nm
and
.Xr carp 4
can be used together to provide automatic failover of a pair of firewalls
configured in parallel.
One firewall handles all traffic \- if it dies or
is shut down, the second firewall takes over automatically.
.Pp
Both firewalls in this example have three
.Xr sis 4
interfaces.
sis0 is the external interface, on the 10.0.0.0/24 subnet; sis1 is the
internal interface, on the 192.168.0.0/24 subnet; and sis2 is the
.Nm
interface, using the 192.168.254.0/24 subnet.
A crossover cable connects the two firewalls via their sis2 interfaces.
On all three interfaces, firewall A uses the .254 address, while firewall B
uses .253.
The interfaces are configured as follows (firewall A unless otherwise
indicated):
.Pp
Interfaces configuration in
.Pa /etc/rc.conf :
.Bd -literal -offset indent
network_interfaces="lo0 sis0 sis1 sis2"
cloned_interfaces="carp0 carp1"
ifconfig_sis0="10.0.0.254/24"
ifconfig_sis1="192.168.0.254/24"
ifconfig_sis2="192.168.254.254/24"
ifconfig_carp0="vhid 1 pass foo 10.0.0.1/24"
ifconfig_carp1="vhid 2 pass bar 192.168.0.1/24"
pfsync_enable="YES"
pfsync_syncdev="sis2"
.Ed
.Pp
.Xr pf 4
must also be configured to allow
.Nm
and
.Xr carp 4
traffic through.
The following should be added to the top of
.Pa /etc/pf.conf :
.Bd -literal -offset indent
pass quick on { sis2 } proto pfsync
pass quick on { sis0 sis1 } proto carp keep state
.Ed
.Pp
If it is preferable that one firewall handle the traffic,
the
.Ar advskew
on the backup firewall's
.Xr carp 4
interfaces should be set to something higher than
the primary's.
For example, if firewall B is the backup, its
carp1 configuration would look like this:
.Bd -literal -offset indent
ifconfig_carp1="vhid 2 pass bar advskew 100 192.168.0.1/24"
.Ed
.Pp
The following must also be added to
.Pa /etc/sysctl.conf :
.Bd -literal -offset indent
net.inet.carp.preempt=1
.Ed
.Sh SEE ALSO
.Xr tcpdump 1 ,
.Xr carp 4 ,
.Xr bpf 4 ,
.Xr inet 4 ,
.Xr inet6 4 ,
sys/conf/files
crypto/rijndael/rijndael-alg-fst.c optional ipsec ipsec_esp
crypto/rijndael/rijndael-api-fst.c optional ipsec ipsec_esp
crypto/sha1.c optional ipsec
crypto/sha1.c optional carp
crypto/sha2/sha2.c optional ipsec
ddb/db_access.c optional ddb
ddb/db_kld.c optional ddb
......
netinet/igmp.c optional inet
netinet/in.c optional inet
netinet/in_cksum.c optional inet
netinet/ip_carp.c optional carp
netinet/ip_gre.c optional gre inet
netinet/ip_id.c optional inet
netinet/in_pcb.c optional inet
sys/conf/options
BOOTP_NFSROOT opt_bootp.h
BOOTP_NFSV3 opt_bootp.h
BOOTP_WIRED_TO opt_bootp.h
CARP opt_carp.h
ETHER_II opt_ef.h
ETHER_8023 opt_ef.h
ETHER_8022 opt_ef.h
sys/config/LINT
device pfsync
device pflog
#CARP
pseudo-device carp
options CARP
# The MBUF_STRESS_TEST option enables options which create
# various random failures / extreme cases related to mbuf
# functions. See the mbuf(9) manpage for a list of available
sys/config/VKERNEL
options DDB_TRACE
options INVARIANTS
options CARP
# Floating point support - do not disable.
device npx0 at nexus?
......
pseudo-device gif # IPv6 and IPv4 tunneling
pseudo-device faith 1 # IPv6-to-IPv4 relaying (translation)
pseudo-device carp
# The `bpf' pseudo-device enables the Berkeley Packet Filter.
# Be aware of the administrative consequences of enabling this!
pseudo-device bpf #Berkeley packet filter
......
device vn
device vkd
device vke
sys/net/if_ethersubr.c
#include "opt_inet6.h"
#include "opt_ipx.h"
#include "opt_netgraph.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/systm.h>
......
#include <netinet6/nd6.h>
#endif
#ifdef CARP
#include <netinet/ip_carp.h>
#endif
#ifdef IPX
#include <netproto/ipx/ipx.h>
#include <netproto/ipx/ipx_if.h>
......
}
}
#ifdef CARP
if (ifp->if_carp && (error = carp_output(ifp, m, dst, NULL)))
goto bad;
#endif
/* Handle ng_ether(4) processing, if any */
if (ng_ether_output_p != NULL) {
if ((error = (*ng_ether_output_p)(ifp, &m)) != 0)
......
if (rule) /* packet is passing the second time */
goto post_stats;
#ifdef 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
......
m_freem(m);
return;
}
#ifdef CARP
pre_stats:
#endif
/* Discard packet if interface is not up */
if (!(ifp->if_flags & IFF_UP)) {
m_freem(m);
sys/net/if_media.h
#define IFM_ATM_UNASSIGNED 0x00000400 /* unassigned cells */
/*
* CARP Common Address Redundancy Protocol
*/
#define IFM_CARP 0x000000c0
/*
* Shared media sub-types
*/
#define IFM_AUTO 0 /* Autoselect best media */
......
{ IFM_TOKEN, "Token ring" }, \
{ IFM_FDDI, "FDDI" }, \
{ IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \
{ IFM_CARP, "Common Address Redundancy Protocol" }, \
{ 0, NULL }, \
}
sys/net/if_types.h
#define IFT_STF 0xf3
#define IFT_PFLOG 0xf5 /* Packet filter logging */
#define IFT_PFSYNC 0xf6 /* Packet filter state syncing */
#define IFT_CARP 0xf8 /* Common Address Redundancy Protocol */
#endif /* !_NET_IF_TYPES_H_ */
sys/net/if_var.h
struct rt_addrinfo;
struct socket;
struct ether_header;
struct carp_if;
struct ucred;
struct lwkt_serialize;
......
int if_dunit; /* unit or IF_DUNIT_NONE */
struct ifaddrhead if_addrhead; /* linked list of addresses per if */
int if_pcount; /* number of promiscuous listeners */
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 */
sys/netinet/if_ether.c
*/
#include "opt_inet.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/kernel.h>
......
#include <net/if_arc.h>
#include <net/iso88025.h>
#ifdef CARP
#include <netinet/ip_carp.h>
#endif
#define SIN(s) ((struct sockaddr_in *)s)
#define SDL(s) ((struct sockaddr_dl *)s)
......
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
&arp_proxyall, 0, "");
void arprequest_acces(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, u_char *enaddr);
static void arp_rtrequest (int, struct rtentry *, struct rt_addrinfo *);
static void arprequest (struct ifnet *,
struct in_addr *, struct in_addr *, u_char *);
......
#ifdef SMP
struct netmsg_arp_update msg;
#endif
u_int8_t *enaddr = NULL;
int op;
int req_len;
......
if (ifp->if_bridge && ia->ia_ifp &&
ifp->if_bridge == ia->ia_ifp->if_bridge)
goto match;
#ifdef CARP
/*
* 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!
*/
if (ifp->if_carp != NULL &&
carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) &&
itaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
goto match;
#endif
}
LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) {
/* Skip all ia's which don't match */
......
return;
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)) {
m_freem(m); /* it's from me, ignore it. */
return;
}
......
if (itaddr.s_addr == myaddr.s_addr) {
/* I am the target */
memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln);
memcpy(ar_sha(ah), enaddr, ah->ar_hln);
} else {
struct llinfo_arp *la;
......
return;
}
memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
memcpy(ar_sha(ah), IF_LLADDR(ifp), ah->ar_hln);
memcpy(ar_sha(ah), enaddr, ah->ar_hln);
#ifdef DEBUG_PROXY
kprintf("arp: proxying for %s\n", inet_ntoa(itaddr));
#endif
......
ifa->ifa_flags |= RTF_CLONING;
}
void
arp_ifinit2(struct ifnet *ifp, struct ifaddr *ifa, u_char *enaddr)
{
if (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)
{
sys/netinet/if_ether.h
int arpresolve (struct ifnet *, struct rtentry *, struct mbuf *,
struct sockaddr *, u_char *);
void arp_ifinit (struct ifnet *, struct ifaddr *);
void arp_ifinit2 (struct ifnet *, struct ifaddr *, u_char *);
#endif
#endif
sys/netinet/in.h
#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_SCTP 132 /* SCTP */
#define IPPROTO_PFSYNC 240 /* PFSYNC */
......
#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_MAX_LOCAL_GROUP (u_int32_t)0xe00000ff /* 224.0.0.255 */
sys/netinet/in_proto.c
#include "opt_ipsec.h"
#include "opt_inet6.h"
#include "opt_sctp.h"
#include "opt_carp.h"
#include <sys/param.h>
#include <sys/kernel.h>
......
#include <net/netisr.h> /* for cpu0_soport */
#ifdef CARP
#include <netinet/ip_carp.h>
#endif
extern struct domain inetdomain;
static struct pr_usrreqs nousrreqs;
......
rip_init, 0, 0, 0,
&rip_usrreqs
},
#ifdef CARP
{ SOCK_RAW, &inetdomain, IPPROTO_CARP, PR_ATOMIC|PR_ADDR,
carp_input, rip_output, 0, rip_ctloutput,
0,
0, 0, 0, 0,
&rip_usrreqs
},
#endif
};
struct domain inetdomain = {
......
#ifdef PIM
SYSCTL_NODE(_net_inet, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
#endif
#ifdef CARP
SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP");
#endif
sys/netinet/ip_carp.c
/* $Id$ */
/* from $FreeBSD: src/sys/netinet/ip_carp.c,v 1.48 2007/02/02 09:39:09 glebius 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 "opt_carp.h"
/*#include "opt_bpf.h"*/
#include "opt_inet.h"
#include "opt_inet6.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <machine/limits.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/signalvar.h>
#include <sys/filio.h>
#include <sys/sockio.h>
#include <sys/in_cksum.h>
#include <sys/socket.h>
#include <sys/vnode.h>
#include <machine/stdarg.h>
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/iso88025.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/if_ether.h>
#include <netinet/if_fddi.h>
#endif
#ifdef INET6
#include <netinet/icmp6.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
#include <netinet6/nd6.h>
#endif
#include <crypto/sha1.h>
#include <netinet/ip_carp.h>
#include <sys/lock.h>
#define CARP_IFNAME "carp"
static MALLOC_DEFINE(M_CARP, "CARP", "CARP interfaces");
static MALLOC_DEFINE(M_IFNET, "IFNET", "IFNET CARP?");
SYSCTL_DECL(_net_inet_carp);
struct carp_softc {
struct ifnet *sc_ifp; /* Interface clue */
struct ifnet *sc_carpdev; /* Pointer to parent interface */
struct in_ifaddr *sc_ia; /* primary iface address */
struct ip_moptions sc_imo;
#ifdef INET6
struct in6_ifaddr *sc_ia6; /* primary iface address v6 */
struct ip6_moptions sc_im6o;
#endif /* INET6 */
TAILQ_ENTRY(carp_softc) sc_list;
enum { INIT = 0, BACKUP, MASTER } sc_state;
int sc_flags_backup;
int sc_suppress;
int sc_sendad_errors;
#define CARP_SENDAD_MAX_ERRORS 3
int sc_sendad_success;
#define CARP_SENDAD_MIN_SUCCESS 3
int sc_vhid;
int sc_advskew;
int sc_naddrs;
int sc_naddrs6;
int sc_advbase; /* seconds */
int sc_init_counter;
u_int64_t sc_counter;
/* authentication */
#define CARP_HMAC_PAD 64
unsigned char sc_key[CARP_KEY_LEN];
unsigned char sc_pad[CARP_HMAC_PAD];
SHA1_CTX sc_sha1;
struct callout sc_ad_tmo; /* advertisement timeout */
struct callout sc_md_tmo; /* master down timeout */
struct callout sc_md6_tmo; /* master down timeout */
LIST_ENTRY(carp_softc) sc_next; /* Interface clue */
};
#define SC2IFP(sc) ((sc)->sc_ifp)
int carp_suppress_preempt = 0;
int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 1, 0, 0 }; /* XXX for now */
SYSCTL_INT(_net_inet_carp, CARPCTL_ALLOW, allow, CTLFLAG_RW,
&carp_opts[CARPCTL_ALLOW], 0, "Accept incoming CARP packets");
SYSCTL_INT(_net_inet_carp, CARPCTL_PREEMPT, preempt, CTLFLAG_RW,
&carp_opts[CARPCTL_PREEMPT], 0, "high-priority backup preemption mode");
SYSCTL_INT(_net_inet_carp, CARPCTL_LOG, log, CTLFLAG_RW,
&carp_opts[CARPCTL_LOG], 0, "log bad carp packets");
SYSCTL_INT(_net_inet_carp, CARPCTL_ARPBALANCE, arpbalance, CTLFLAG_RW,
&carp_opts[CARPCTL_ARPBALANCE], 0, "balance arp responses");
SYSCTL_INT(_net_inet_carp, OID_AUTO, suppress_preempt, CTLFLAG_RD,
&carp_suppress_preempt, 0, "Preemption is suppressed");
struct carpstats carpstats;
SYSCTL_STRUCT(_net_inet_carp, CARPCTL_STATS, stats, CTLFLAG_RW,
&carpstats, carpstats,
"CARP statistics (struct carpstats, netinet/ip_carp.h)");
struct carp_if {
TAILQ_HEAD(, carp_softc) vhif_vrs;
int vhif_nvrs;
struct ifnet *vhif_ifp;
struct lock vhif_lock;
};
/* Get carp_if from softc. Valid after carp_set_addr{,6}. */
#define SC2CIF(sc) ((struct carp_if *)(sc)->sc_carpdev->if_carp)
#define CARP_LOCK_INIT(cif) lockinit(&(cif)->vhif_lock, "carp_if", 0, LK_NOWAIT);
#define CARP_LOCK_DESTROY(cif) ;
#define CARP_LOCK_ASSERT(cif) ;
#define CARP_LOCK(cif) lockmgr(&(cif)->vhif_lock, LK_EXCLUSIVE);
#define CARP_UNLOCK(cif) lockmgr(&(cif)->vhif_lock, LK_RELEASE);
#define CARP_SCLOCK(sc) lockmgr(&SC2CIF(sc)->vhif_lock, LK_EXCLUSIVE);
#define CARP_SCUNLOCK(sc) lockmgr(&SC2CIF(sc)->vhif_lock, LK_RELEASE);
#define CARP_SCLOCK_ASSERT(sc) ;
#define CARP_LOG(...) do { \
if (carp_opts[CARPCTL_LOG] > 0) \
log(LOG_INFO, __VA_ARGS__); \
} while (0)
#define CARP_DEBUG(...) do { \
if (carp_opts[CARPCTL_LOG] > 1) \
log(LOG_DEBUG, __VA_ARGS__); \
} while (0)
static void carp_hmac_prepare(struct carp_softc *);
static void carp_hmac_generate(struct carp_softc *, u_int32_t *,
unsigned char *);
static int carp_hmac_verify(struct carp_softc *, u_int32_t *,
unsigned char *);
static void carp_setroute(struct carp_softc *, int);
static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
static int carp_clone_create(struct if_clone *, int);
static void carp_clone_destroy(struct ifnet *);
static void carpdetach(struct carp_softc *, int);
static int carp_prepare_ad(struct mbuf *, struct carp_softc *,
struct carp_header *);
static void carp_send_ad_all(void);
static void carp_send_ad(void *);
static void carp_send_ad_locked(struct carp_softc *);
static void carp_send_arp(struct carp_softc *);
static void carp_master_down(void *);
static void carp_master_down_locked(struct carp_softc *);
static int carp_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
static int carp_looutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
static void carp_start(struct ifnet *);
static void carp_setrun(struct carp_softc *, sa_family_t);
static void carp_set_state(struct carp_softc *, int);
static int carp_addrcount(struct carp_if *, struct in_ifaddr *, int);
enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING };
static void carp_multicast_cleanup(struct carp_softc *);
static int carp_set_addr(struct carp_softc *, struct sockaddr_in *);
static int carp_del_addr(struct carp_softc *, struct sockaddr_in *);
static void carp_carpdev_state_locked(struct carp_if *);
static void carp_sc_state_locked(struct carp_softc *);
#ifdef INET6
static void carp_send_na(struct carp_softc *);
static int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
static int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *);
static void carp_multicast6_cleanup(struct carp_softc *);
#endif
static LIST_HEAD(, carp_softc) carpif_list;
struct if_clone carp_cloner = IF_CLONE_INITIALIZER(CARP_IFNAME, carp_clone_create, carp_clone_destroy, 0, IF_MAXUNIT);
static eventhandler_tag if_detach_event_tag;
static __inline u_int16_t
carp_cksum(struct mbuf *m, int len)
{
return (in_cksum(m, len));
}
static void
carp_hmac_prepare(struct carp_softc *sc)
{
u_int8_t version = CARP_VERSION, type = CARP_ADVERTISEMENT;
u_int8_t vhid = sc->sc_vhid & 0xff;
struct ifaddr *ifa;
int i;
#ifdef INET6
struct in6_addr in6;
#endif
if (sc->sc_carpdev)
CARP_SCLOCK(sc);
/* XXX: possible race here */
/* compute ipad from key */
bzero(sc->sc_pad, sizeof(sc->sc_pad));
bcopy(sc->sc_key, sc->sc_pad, sizeof(sc->sc_key));
for (i = 0; i < sizeof(sc->sc_pad); i++)
sc->sc_pad[i] ^= 0x36;
/* precompute first part of inner hash */
SHA1Init(&sc->sc_sha1);
SHA1Update(&sc->sc_sha1, sc->sc_pad, sizeof(sc->sc_pad));
SHA1Update(&sc->sc_sha1, (void *)&version, sizeof(version));
SHA1Update(&sc->sc_sha1, (void *)&type, sizeof(type));
SHA1Update(&sc->sc_sha1, (void *)&vhid, sizeof(vhid));
#ifdef INET
TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family == AF_INET)
SHA1Update(&sc->sc_sha1,
(void *)&ifatoia(ifa)->ia_addr.sin_addr.s_addr,
sizeof(struct in_addr));
}
#endif /* INET */
#ifdef INET6
TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family == AF_INET6) {
in6 = ifatoia6(ifa)->ia_addr.sin6_addr;
in6_clearscope(&in6);
SHA1Update(&sc->sc_sha1, (void *)&in6, sizeof(in6));
}
}
#endif /* INET6 */
/* convert ipad to opad */
for (i = 0; i < sizeof(sc->sc_pad); i++)
sc->sc_pad[i] ^= 0x36 ^ 0x5c;
if (sc->sc_carpdev)
CARP_SCUNLOCK(sc);
}
static void
carp_hmac_generate(struct carp_softc *sc, u_int32_t counter[2],
unsigned char md[20])
{
SHA1_CTX sha1ctx;
/* fetch first half of inner hash */
bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx));
SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter));
SHA1Final(md, &sha1ctx);
/* outer hash */
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad));
SHA1Update(&sha1ctx, md, 20);
SHA1Final(md, &sha1ctx);
}
static int
carp_hmac_verify(struct carp_softc *sc, u_int32_t counter[2],
unsigned char md[20])
{
unsigned char md2[20];
CARP_SCLOCK_ASSERT(sc);
carp_hmac_generate(sc, counter, md2);
return (bcmp(md, md2, sizeof(md2)));
}
static void
carp_setroute(struct carp_softc *sc, int cmd)
{
struct ifaddr *ifa;
if (sc->sc_carpdev)
CARP_SCLOCK_ASSERT(sc);
crit_enter();
TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family == AF_INET &&
sc->sc_carpdev != NULL) {
int 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))
rtinit(ifa, cmd, RTF_UP | RTF_HOST);
}
#ifdef INET6
if (ifa->ifa_addr->sa_family == AF_INET6) {
if (cmd == RTM_ADD)
in6_ifaddloop(ifa);
else
in6_ifremloop(ifa);
}
#endif /* INET6 */
}
crit_exit();
}
static int
carp_clone_create(struct if_clone *ifc, int unit)
{
struct carp_softc *sc;
struct ifnet *ifp;
MALLOC(sc, struct carp_softc *, sizeof(*sc), M_CARP, M_WAITOK|M_ZERO);
ifp = SC2IFP(sc) = kmalloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO);
if (ifp == NULL) {
FREE(sc, M_CARP);
return (ENOSPC);
}
sc->sc_flags_backup = 0;
sc->sc_suppress = 0;
sc->sc_advbase = CARP_DFLTINTV;
sc->sc_vhid = -1; /* required setting */
sc->sc_advskew = 0;
sc->sc_init_counter = 1;
sc->sc_naddrs = sc->sc_naddrs6 = 0; /* M_ZERO? */
#ifdef INET6
sc->sc_im6o.im6o_multicast_hlim = CARP_DFLTTL;
#endif
/* sc->sc_imo.imo_membership = kmalloc((sizeof(struct in_multi) * IP_MAX_MEMBERSHIPS), M_CARP,M_WAITOK);*/
/*
sc->sc_imo.imo_max_memberships = IP_MAX_MEMBERSHIPS;
sc->sc_imo.imo_multicast_vif = -1;
*/
callout_init(&sc->sc_ad_tmo);
callout_init(&sc->sc_md_tmo);
callout_init(&sc->sc_md6_tmo);
ifp->if_softc = sc;
if_initname(ifp, CARP_IFNAME, unit);
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_LOOPBACK;
ifp->if_ioctl = carp_ioctl;
ifp->if_output = carp_looutput;
ifp->if_start = carp_start;
ifp->if_type = IFT_CARP;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = 0;
if_attach(ifp, NULL);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
crit_enter();
LIST_INSERT_HEAD(&carpif_list, sc, sc_next);
crit_exit();
return (0);
}
static void
carp_clone_destroy(struct ifnet *ifp)
{
struct carp_softc *sc = ifp->if_softc;
if (sc->sc_carpdev)
CARP_SCLOCK(sc);
carpdetach(sc, 1); /* Returns unlocked. */
crit_enter();
LIST_REMOVE(sc, sc_next);
crit_exit();
bpfdetach(ifp);
if_detach(ifp);
/* if_free_type(ifp, IFT_ETHER);*/
/* kfree(sc->sc_imo.imo_membership, M_CARP); */
kfree(sc, M_CARP);
}
/*
* This function can be called on CARP interface destroy path,
* and in case of the removal of the underlying interface as
* well. We differentiate these two cases. In the latter case
* we do not cleanup our multicast memberships, since they
* are already freed. Also, in the latter case we do not
* release the lock on return, because the function will be
* called once more, for another CARP instance on the same
* interface.
*/
... This diff was truncated because it exceeds the maximum size that can be displayed.
(2-2/2)