ip_carp.c (227459) | ip_carp.c (228571) |
---|---|
1/* 2 * Copyright (c) 2002 Michael Shalayeff. All rights reserved. 3 * Copyright (c) 2003 Ryan McBride. All rights reserved. | 1/*- 2 * Copyright (c) 2002 Michael Shalayeff. 3 * Copyright (c) 2003 Ryan McBride. 4 * Copyright (c) 2011 Gleb Smirnoff <glebius@FreeBSD.org> 5 * All rights reserved. |
4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the --- 8 unchanged lines hidden (view full) --- 20 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 * THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> | 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the --- 8 unchanged lines hidden (view full) --- 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: head/sys/netinet/ip_carp.c 227459 2011-11-11 22:57:52Z brooks $"); | 30__FBSDID("$FreeBSD: head/sys/netinet/ip_carp.c 228571 2011-12-16 12:16:56Z glebius $"); |
29 30#include "opt_bpf.h" 31#include "opt_inet.h" 32#include "opt_inet6.h" 33 | 31 32#include "opt_bpf.h" 33#include "opt_inet.h" 34#include "opt_inet6.h" 35 |
34#include <sys/types.h> | |
35#include <sys/param.h> 36#include <sys/systm.h> | 36#include <sys/param.h> 37#include <sys/systm.h> |
37#include <sys/conf.h> | 38#include <sys/bus.h> 39#include <sys/jail.h> |
38#include <sys/kernel.h> 39#include <sys/limits.h> 40#include <sys/malloc.h> 41#include <sys/mbuf.h> 42#include <sys/module.h> | 40#include <sys/kernel.h> 41#include <sys/limits.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/module.h> |
43#include <sys/time.h> | |
44#include <sys/priv.h> 45#include <sys/proc.h> 46#include <sys/protosw.h> | 45#include <sys/priv.h> 46#include <sys/proc.h> 47#include <sys/protosw.h> |
48#include <sys/socket.h> 49#include <sys/sockio.h> |
|
47#include <sys/sysctl.h> 48#include <sys/syslog.h> | 50#include <sys/sysctl.h> 51#include <sys/syslog.h> |
49#include <sys/signalvar.h> 50#include <sys/filio.h> 51#include <sys/sockio.h> | |
52 | 52 |
53#include <sys/socket.h> 54#include <sys/vnode.h> 55 56#include <machine/stdarg.h> 57 58#include <net/bpf.h> | |
59#include <net/ethernet.h> 60#include <net/fddi.h> | 53#include <net/ethernet.h> 54#include <net/fddi.h> |
61#include <net/iso88025.h> | |
62#include <net/if.h> | 55#include <net/if.h> |
63#include <net/if_clone.h> | |
64#include <net/if_dl.h> | 56#include <net/if_dl.h> |
57#include <net/if_llatbl.h> |
|
65#include <net/if_types.h> | 58#include <net/if_types.h> |
59#include <net/iso88025.h> |
|
66#include <net/route.h> 67#include <net/vnet.h> 68 69#if defined(INET) || defined(INET6) 70#include <netinet/in.h> 71#include <netinet/in_var.h> 72#include <netinet/ip_carp.h> 73#include <netinet/ip.h> | 60#include <net/route.h> 61#include <net/vnet.h> 62 63#if defined(INET) || defined(INET6) 64#include <netinet/in.h> 65#include <netinet/in_var.h> 66#include <netinet/ip_carp.h> 67#include <netinet/ip.h> |
74 | |
75#include <machine/in_cksum.h> 76#endif | 68#include <machine/in_cksum.h> 69#endif |
77 | |
78#ifdef INET | 70#ifdef INET |
79#include <netinet/in_systm.h> | |
80#include <netinet/ip_var.h> 81#include <netinet/if_ether.h> 82#endif 83 84#ifdef INET6 85#include <netinet/icmp6.h> 86#include <netinet/ip6.h> 87#include <netinet6/ip6protosw.h> | 71#include <netinet/ip_var.h> 72#include <netinet/if_ether.h> 73#endif 74 75#ifdef INET6 76#include <netinet/icmp6.h> 77#include <netinet/ip6.h> 78#include <netinet6/ip6protosw.h> |
79#include <netinet6/in6_var.h> |
|
88#include <netinet6/ip6_var.h> 89#include <netinet6/scope6_var.h> | 80#include <netinet6/ip6_var.h> 81#include <netinet6/scope6_var.h> |
90#include <netinet6/in6_var.h> | |
91#include <netinet6/nd6.h> 92#endif 93 94#include <crypto/sha1.h> 95 | 82#include <netinet6/nd6.h> 83#endif 84 85#include <crypto/sha1.h> 86 |
96#define CARP_IFNAME "carp" 97static MALLOC_DEFINE(M_CARP, "CARP", "CARP interfaces"); 98SYSCTL_DECL(_net_inet_carp); | 87static MALLOC_DEFINE(M_CARP, "CARP", "CARP addresses"); |
99 100struct carp_softc { | 88 89struct carp_softc { |
101 struct ifnet *sc_ifp; /* Interface clue */ 102 struct ifnet *sc_carpdev; /* Pointer to parent interface */ 103 struct in_ifaddr *sc_ia; /* primary iface address */ | 90 struct ifnet *sc_carpdev; /* Pointer to parent ifnet. */ 91 struct ifaddr **sc_ifas; /* Our ifaddrs. */ 92 struct sockaddr_dl sc_addr; /* Our link level address. */ 93 struct callout sc_ad_tmo; /* Advertising timeout. */ |
104#ifdef INET | 94#ifdef INET |
105 struct ip_moptions sc_imo; | 95 struct callout sc_md_tmo; /* Master down timeout. */ |
106#endif 107#ifdef INET6 | 96#endif 97#ifdef INET6 |
108 struct in6_ifaddr *sc_ia6; /* primary iface address v6 */ 109 struct ip6_moptions sc_im6o; 110#endif /* INET6 */ 111 TAILQ_ENTRY(carp_softc) sc_list; | 98 struct callout sc_md6_tmo; /* XXX: Master down timeout. */ 99#endif 100 struct mtx sc_mtx; |
112 | 101 |
113 enum { INIT = 0, BACKUP, MASTER } sc_state; | 102 int sc_vhid; 103 int sc_advskew; 104 int sc_advbase; |
114 | 105 |
115 int sc_flags_backup; 116 int sc_suppress; 117 118 int sc_sendad_errors; | 106 int sc_naddrs; 107 int sc_naddrs6; 108 int sc_ifasiz; 109 enum { INIT = 0, BACKUP, MASTER } sc_state; 110 int sc_suppress; 111 int sc_sendad_errors; |
119#define CARP_SENDAD_MAX_ERRORS 3 | 112#define CARP_SENDAD_MAX_ERRORS 3 |
120 int sc_sendad_success; | 113 int sc_sendad_success; |
121#define CARP_SENDAD_MIN_SUCCESS 3 122 | 114#define CARP_SENDAD_MIN_SUCCESS 3 115 |
123 int sc_vhid; 124 int sc_advskew; 125 int sc_naddrs; 126 int sc_naddrs6; 127 int sc_advbase; /* seconds */ 128 int sc_init_counter; 129 u_int64_t sc_counter; | 116 int sc_init_counter; 117 uint64_t sc_counter; |
130 131 /* authentication */ | 118 119 /* authentication */ |
132#define CARP_HMAC_PAD 64 | 120#define CARP_HMAC_PAD 64 |
133 unsigned char sc_key[CARP_KEY_LEN]; 134 unsigned char sc_pad[CARP_HMAC_PAD]; 135 SHA1_CTX sc_sha1; 136 | 121 unsigned char sc_key[CARP_KEY_LEN]; 122 unsigned char sc_pad[CARP_HMAC_PAD]; 123 SHA1_CTX sc_sha1; 124 |
137 struct callout sc_ad_tmo; /* advertisement timeout */ 138 struct callout sc_md_tmo; /* master down timeout */ 139 struct callout sc_md6_tmo; /* master down timeout */ 140 141 LIST_ENTRY(carp_softc) sc_next; /* Interface clue */ | 125 TAILQ_ENTRY(carp_softc) sc_list; /* On the carp_if list. */ 126 LIST_ENTRY(carp_softc) sc_next; /* On the global list. */ |
142}; | 127}; |
143#define SC2IFP(sc) ((sc)->sc_ifp) | |
144 | 128 |
129struct carp_if { 130#ifdef INET 131 int cif_naddrs; 132#endif 133#ifdef INET6 134 int cif_naddrs6; 135#endif 136 TAILQ_HEAD(, carp_softc) cif_vrs; 137#ifdef INET 138 struct ip_moptions cif_imo; 139#endif 140#ifdef INET6 141 struct ip6_moptions cif_im6o; 142#endif 143 struct ifnet *cif_ifp; 144 struct mtx cif_mtx; 145}; 146 147#define CARP_INET 0 148#define CARP_INET6 1 149static int proto_reg[] = {-1, -1}; 150 151/* 152 * Brief design of carp(4). 153 * 154 * Any carp-capable ifnet may have a list of carp softcs hanging off 155 * its ifp->if_carp pointer. Each softc represents one unique virtual 156 * host id, or vhid. The softc has a back pointer to the ifnet. All 157 * softcs are joined in a global list, which has quite limited use. 158 * 159 * Any interface address that takes part in CARP negotiation has a 160 * pointer to the softc of its vhid, ifa->ifa_carp. That could be either 161 * AF_INET or AF_INET6 address. 162 * 163 * Although, one can get the softc's backpointer to ifnet and traverse 164 * through its ifp->if_addrhead queue to find all interface addresses 165 * involved in CARP, we keep a growable array of ifaddr pointers. This 166 * allows us to avoid grabbing the IF_ADDR_LOCK() in many traversals that 167 * do calls into the network stack, thus avoiding LORs. 168 * 169 * Locking: 170 * 171 * Each softc has a lock sc_mtx. It is used to synchronise carp_input_c(), 172 * callout-driven events and ioctl()s. 173 * 174 * To traverse the list of softcs on an ifnet we use CIF_LOCK(), to 175 * traverse the global list we use the mutex carp_mtx. 176 * 177 * Known issues with locking: 178 * 179 * - There is no protection for races between two ioctl() requests, 180 * neither SIOCSVH, nor SIOCAIFADDR & SIOCAIFADDR_IN6. I think that all 181 * interface ioctl()s should be serialized right in net/if.c. 182 * - Sending ad, we put the pointer to the softc in an mtag, and no reference 183 * counting is done on the softc. 184 * - On module unload we may race (?) with packet processing thread 185 * dereferencing our function pointers. 186 */ 187 |
|
145int carp_suppress_preempt = 0; | 188int carp_suppress_preempt = 0; |
146int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 1, 0, 0 }; /* XXX for now */ | 189int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 1, 0, }; |
147SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); 148SYSCTL_INT(_net_inet_carp, CARPCTL_ALLOW, allow, CTLFLAG_RW, 149 &carp_opts[CARPCTL_ALLOW], 0, "Accept incoming CARP packets"); 150SYSCTL_INT(_net_inet_carp, CARPCTL_PREEMPT, preempt, CTLFLAG_RW, 151 &carp_opts[CARPCTL_PREEMPT], 0, "high-priority backup preemption mode"); 152SYSCTL_INT(_net_inet_carp, CARPCTL_LOG, log, CTLFLAG_RW, 153 &carp_opts[CARPCTL_LOG], 0, "log bad carp packets"); | 190SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); 191SYSCTL_INT(_net_inet_carp, CARPCTL_ALLOW, allow, CTLFLAG_RW, 192 &carp_opts[CARPCTL_ALLOW], 0, "Accept incoming CARP packets"); 193SYSCTL_INT(_net_inet_carp, CARPCTL_PREEMPT, preempt, CTLFLAG_RW, 194 &carp_opts[CARPCTL_PREEMPT], 0, "high-priority backup preemption mode"); 195SYSCTL_INT(_net_inet_carp, CARPCTL_LOG, log, CTLFLAG_RW, 196 &carp_opts[CARPCTL_LOG], 0, "log bad carp packets"); |
154SYSCTL_INT(_net_inet_carp, CARPCTL_ARPBALANCE, arpbalance, CTLFLAG_RW, 155 &carp_opts[CARPCTL_ARPBALANCE], 0, "balance arp responses"); | |
156SYSCTL_INT(_net_inet_carp, OID_AUTO, suppress_preempt, CTLFLAG_RD, 157 &carp_suppress_preempt, 0, "Preemption is suppressed"); 158 159struct carpstats carpstats; 160SYSCTL_STRUCT(_net_inet_carp, CARPCTL_STATS, stats, CTLFLAG_RW, 161 &carpstats, carpstats, 162 "CARP statistics (struct carpstats, netinet/ip_carp.h)"); 163 | 197SYSCTL_INT(_net_inet_carp, OID_AUTO, suppress_preempt, CTLFLAG_RD, 198 &carp_suppress_preempt, 0, "Preemption is suppressed"); 199 200struct carpstats carpstats; 201SYSCTL_STRUCT(_net_inet_carp, CARPCTL_STATS, stats, CTLFLAG_RW, 202 &carpstats, carpstats, 203 "CARP statistics (struct carpstats, netinet/ip_carp.h)"); 204 |
164struct carp_if { 165 TAILQ_HEAD(, carp_softc) vhif_vrs; 166 int vhif_nvrs; 167 168 struct ifnet *vhif_ifp; 169 struct mtx vhif_mtx; 170}; 171 172#define CARP_INET 0 173#define CARP_INET6 1 174static int proto_reg[] = {-1, -1}; 175 176/* Get carp_if from softc. Valid after carp_set_addr{,6}. */ 177#define SC2CIF(sc) ((struct carp_if *)(sc)->sc_carpdev->if_carp) 178 179/* lock per carp_if queue */ 180#define CARP_LOCK_INIT(cif) mtx_init(&(cif)->vhif_mtx, "carp_if", \ | 205#define CARP_LOCK_INIT(sc) mtx_init(&(sc)->sc_mtx, "carp_softc", \ |
181 NULL, MTX_DEF) | 206 NULL, MTX_DEF) |
182#define CARP_LOCK_DESTROY(cif) mtx_destroy(&(cif)->vhif_mtx) 183#define CARP_LOCK_ASSERT(cif) mtx_assert(&(cif)->vhif_mtx, MA_OWNED) 184#define CARP_LOCK(cif) mtx_lock(&(cif)->vhif_mtx) 185#define CARP_UNLOCK(cif) mtx_unlock(&(cif)->vhif_mtx) | 207#define CARP_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) 208#define CARP_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) 209#define CARP_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 210#define CARP_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 211#define CIF_LOCK_INIT(cif) mtx_init(&(cif)->cif_mtx, "carp_if", \ 212 NULL, MTX_DEF) 213#define CIF_LOCK_DESTROY(cif) mtx_destroy(&(cif)->cif_mtx) 214#define CIF_LOCK_ASSERT(cif) mtx_assert(&(cif)->cif_mtx, MA_OWNED) 215#define CIF_LOCK(cif) mtx_lock(&(cif)->cif_mtx) 216#define CIF_UNLOCK(cif) mtx_unlock(&(cif)->cif_mtx) |
186 | 217 |
187#define CARP_SCLOCK(sc) mtx_lock(&SC2CIF(sc)->vhif_mtx) 188#define CARP_SCUNLOCK(sc) mtx_unlock(&SC2CIF(sc)->vhif_mtx) 189#define CARP_SCLOCK_ASSERT(sc) mtx_assert(&SC2CIF(sc)->vhif_mtx, MA_OWNED) 190 | |
191#define CARP_LOG(...) do { \ 192 if (carp_opts[CARPCTL_LOG] > 0) \ | 218#define CARP_LOG(...) do { \ 219 if (carp_opts[CARPCTL_LOG] > 0) \ |
193 log(LOG_INFO, __VA_ARGS__); \ | 220 log(LOG_INFO, "carp: " __VA_ARGS__); \ |
194} while (0) 195 196#define CARP_DEBUG(...) do { \ 197 if (carp_opts[CARPCTL_LOG] > 1) \ 198 log(LOG_DEBUG, __VA_ARGS__); \ 199} while (0) 200 | 221} while (0) 222 223#define CARP_DEBUG(...) do { \ 224 if (carp_opts[CARPCTL_LOG] > 1) \ 225 log(LOG_DEBUG, __VA_ARGS__); \ 226} while (0) 227 |
201static void carp_hmac_prepare(struct carp_softc *); 202static void carp_hmac_generate(struct carp_softc *, u_int32_t *, 203 unsigned char *); 204static int carp_hmac_verify(struct carp_softc *, u_int32_t *, 205 unsigned char *); 206static void carp_setroute(struct carp_softc *, int); | 228#define IFNET_FOREACH_IFA(ifp, ifa) \ 229 IF_ADDR_LOCK_ASSERT(ifp); \ 230 TAILQ_FOREACH((ifa), &(ifp)->if_addrhead, ifa_link) \ 231 if ((ifa)->ifa_carp != NULL) 232 233#define CARP_FOREACH_IFA(sc, ifa) \ 234 CARP_LOCK_ASSERT(sc); \ 235 for (int _i = 0; \ 236 _i < (sc)->sc_naddrs + (sc)->sc_naddrs6 && \ 237 ((ifa) = sc->sc_ifas[_i]) != NULL; \ 238 ++_i) 239 240#define IFNET_FOREACH_CARP(ifp, sc) \ 241 CIF_LOCK_ASSERT(ifp->if_carp); \ 242 TAILQ_FOREACH((sc), &(ifp)->if_carp->cif_vrs, sc_list) 243 |
207static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t); | 244static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t); |
208static int carp_clone_create(struct if_clone *, int, caddr_t); 209static void carp_clone_destroy(struct ifnet *); 210static void carpdetach(struct carp_softc *, int); 211static int carp_prepare_ad(struct mbuf *, struct carp_softc *, 212 struct carp_header *); 213static void carp_send_ad_all(void); 214static void carp_send_ad(void *); 215static void carp_send_ad_locked(struct carp_softc *); 216#ifdef INET 217static void carp_send_arp(struct carp_softc *); 218#endif | 245static struct carp_softc 246 *carp_alloc(struct ifnet *); 247static void carp_destroy(struct carp_softc *); 248static struct carp_if 249 *carp_alloc_if(struct ifnet *); 250static void carp_free_if(struct carp_if *); 251static void carp_set_state(struct carp_softc *, int); 252static void carp_sc_state(struct carp_softc *); 253static void carp_setrun(struct carp_softc *, sa_family_t); |
219static void carp_master_down(void *); 220static void carp_master_down_locked(struct carp_softc *); | 254static void carp_master_down(void *); 255static void carp_master_down_locked(struct carp_softc *); |
221static int carp_ioctl(struct ifnet *, u_long, caddr_t); 222static int carp_looutput(struct ifnet *, struct mbuf *, struct sockaddr *, 223 struct route *); 224static void carp_start(struct ifnet *); 225static void carp_setrun(struct carp_softc *, sa_family_t); 226static void carp_set_state(struct carp_softc *, int); 227#ifdef INET 228static int carp_addrcount(struct carp_if *, struct in_ifaddr *, int); 229#endif 230enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING }; | 256static void carp_send_ad(void *); 257static void carp_send_ad_locked(struct carp_softc *); 258static void carp_addroute(struct carp_softc *); 259static void carp_delroute(struct carp_softc *); |
231 | 260 |
232#ifdef INET 233static void carp_multicast_cleanup(struct carp_softc *, int dofree); 234static int carp_set_addr(struct carp_softc *, struct sockaddr_in *); 235static int carp_del_addr(struct carp_softc *, struct sockaddr_in *); 236#endif 237static void carp_carpdev_state_locked(struct carp_if *); 238static void carp_sc_state_locked(struct carp_softc *); 239#ifdef INET6 240static void carp_send_na(struct carp_softc *); 241static int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *); 242static int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *); 243static void carp_multicast6_cleanup(struct carp_softc *, int dofree); 244#endif 245 246static LIST_HEAD(, carp_softc) carpif_list; | 261static LIST_HEAD(, carp_softc) carp_list; |
247static struct mtx carp_mtx; | 262static struct mtx carp_mtx; |
248IFC_SIMPLE_DECLARE(carp, 0); | |
249 | 263 |
250static eventhandler_tag if_detach_event_tag; 251 252static __inline u_int16_t | 264static __inline uint16_t |
253carp_cksum(struct mbuf *m, int len) 254{ 255 return (in_cksum(m, len)); 256} 257 258static void 259carp_hmac_prepare(struct carp_softc *sc) 260{ | 265carp_cksum(struct mbuf *m, int len) 266{ 267 return (in_cksum(m, len)); 268} 269 270static void 271carp_hmac_prepare(struct carp_softc *sc) 272{ |
261 u_int8_t version = CARP_VERSION, type = CARP_ADVERTISEMENT; 262 u_int8_t vhid = sc->sc_vhid & 0xff; | 273 uint8_t version = CARP_VERSION, type = CARP_ADVERTISEMENT; 274 uint8_t vhid = sc->sc_vhid & 0xff; |
263 struct ifaddr *ifa; 264 int i, found; 265#ifdef INET 266 struct in_addr last, cur, in; 267#endif 268#ifdef INET6 269 struct in6_addr last6, cur6, in6; 270#endif 271 | 275 struct ifaddr *ifa; 276 int i, found; 277#ifdef INET 278 struct in_addr last, cur, in; 279#endif 280#ifdef INET6 281 struct in6_addr last6, cur6, in6; 282#endif 283 |
272 if (sc->sc_carpdev) 273 CARP_SCLOCK(sc); | 284 CARP_LOCK_ASSERT(sc); |
274 | 285 |
275 /* XXX: possible race here */ 276 277 /* compute ipad from key */ | 286 /* Compute ipad from key. */ |
278 bzero(sc->sc_pad, sizeof(sc->sc_pad)); 279 bcopy(sc->sc_key, sc->sc_pad, sizeof(sc->sc_key)); 280 for (i = 0; i < sizeof(sc->sc_pad); i++) 281 sc->sc_pad[i] ^= 0x36; 282 | 287 bzero(sc->sc_pad, sizeof(sc->sc_pad)); 288 bcopy(sc->sc_key, sc->sc_pad, sizeof(sc->sc_key)); 289 for (i = 0; i < sizeof(sc->sc_pad); i++) 290 sc->sc_pad[i] ^= 0x36; 291 |
283 /* precompute first part of inner hash */ | 292 /* Precompute first part of inner hash. */ |
284 SHA1Init(&sc->sc_sha1); 285 SHA1Update(&sc->sc_sha1, sc->sc_pad, sizeof(sc->sc_pad)); 286 SHA1Update(&sc->sc_sha1, (void *)&version, sizeof(version)); 287 SHA1Update(&sc->sc_sha1, (void *)&type, sizeof(type)); 288 SHA1Update(&sc->sc_sha1, (void *)&vhid, sizeof(vhid)); 289#ifdef INET 290 cur.s_addr = 0; 291 do { 292 found = 0; 293 last = cur; 294 cur.s_addr = 0xffffffff; | 293 SHA1Init(&sc->sc_sha1); 294 SHA1Update(&sc->sc_sha1, sc->sc_pad, sizeof(sc->sc_pad)); 295 SHA1Update(&sc->sc_sha1, (void *)&version, sizeof(version)); 296 SHA1Update(&sc->sc_sha1, (void *)&type, sizeof(type)); 297 SHA1Update(&sc->sc_sha1, (void *)&vhid, sizeof(vhid)); 298#ifdef INET 299 cur.s_addr = 0; 300 do { 301 found = 0; 302 last = cur; 303 cur.s_addr = 0xffffffff; |
295 IF_ADDR_LOCK(SC2IFP(sc)); 296 TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { | 304 CARP_FOREACH_IFA(sc, ifa) { |
297 in.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; 298 if (ifa->ifa_addr->sa_family == AF_INET && 299 ntohl(in.s_addr) > ntohl(last.s_addr) && 300 ntohl(in.s_addr) < ntohl(cur.s_addr)) { 301 cur.s_addr = in.s_addr; 302 found++; 303 } 304 } | 305 in.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; 306 if (ifa->ifa_addr->sa_family == AF_INET && 307 ntohl(in.s_addr) > ntohl(last.s_addr) && 308 ntohl(in.s_addr) < ntohl(cur.s_addr)) { 309 cur.s_addr = in.s_addr; 310 found++; 311 } 312 } |
305 IF_ADDR_UNLOCK(SC2IFP(sc)); | |
306 if (found) 307 SHA1Update(&sc->sc_sha1, (void *)&cur, sizeof(cur)); 308 } while (found); 309#endif /* INET */ 310#ifdef INET6 311 memset(&cur6, 0, sizeof(cur6)); 312 do { 313 found = 0; 314 last6 = cur6; 315 memset(&cur6, 0xff, sizeof(cur6)); | 313 if (found) 314 SHA1Update(&sc->sc_sha1, (void *)&cur, sizeof(cur)); 315 } while (found); 316#endif /* INET */ 317#ifdef INET6 318 memset(&cur6, 0, sizeof(cur6)); 319 do { 320 found = 0; 321 last6 = cur6; 322 memset(&cur6, 0xff, sizeof(cur6)); |
316 IF_ADDR_LOCK(SC2IFP(sc)); 317 TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { | 323 CARP_FOREACH_IFA(sc, ifa) { |
318 in6 = ifatoia6(ifa)->ia_addr.sin6_addr; 319 if (IN6_IS_SCOPE_EMBED(&in6)) 320 in6.s6_addr16[1] = 0; 321 if (ifa->ifa_addr->sa_family == AF_INET6 && 322 memcmp(&in6, &last6, sizeof(in6)) > 0 && 323 memcmp(&in6, &cur6, sizeof(in6)) < 0) { 324 cur6 = in6; 325 found++; 326 } 327 } | 324 in6 = ifatoia6(ifa)->ia_addr.sin6_addr; 325 if (IN6_IS_SCOPE_EMBED(&in6)) 326 in6.s6_addr16[1] = 0; 327 if (ifa->ifa_addr->sa_family == AF_INET6 && 328 memcmp(&in6, &last6, sizeof(in6)) > 0 && 329 memcmp(&in6, &cur6, sizeof(in6)) < 0) { 330 cur6 = in6; 331 found++; 332 } 333 } |
328 IF_ADDR_UNLOCK(SC2IFP(sc)); | |
329 if (found) 330 SHA1Update(&sc->sc_sha1, (void *)&cur6, sizeof(cur6)); 331 } while (found); 332#endif /* INET6 */ 333 334 /* convert ipad to opad */ 335 for (i = 0; i < sizeof(sc->sc_pad); i++) 336 sc->sc_pad[i] ^= 0x36 ^ 0x5c; | 334 if (found) 335 SHA1Update(&sc->sc_sha1, (void *)&cur6, sizeof(cur6)); 336 } while (found); 337#endif /* INET6 */ 338 339 /* convert ipad to opad */ 340 for (i = 0; i < sizeof(sc->sc_pad); i++) 341 sc->sc_pad[i] ^= 0x36 ^ 0x5c; |
337 338 if (sc->sc_carpdev) 339 CARP_SCUNLOCK(sc); | |
340} 341 342static void | 342} 343 344static void |
343carp_hmac_generate(struct carp_softc *sc, u_int32_t counter[2], | 345carp_hmac_generate(struct carp_softc *sc, uint32_t counter[2], |
344 unsigned char md[20]) 345{ 346 SHA1_CTX sha1ctx; 347 | 346 unsigned char md[20]) 347{ 348 SHA1_CTX sha1ctx; 349 |
350 CARP_LOCK_ASSERT(sc); 351 |
|
348 /* fetch first half of inner hash */ 349 bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx)); 350 351 SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter)); 352 SHA1Final(md, &sha1ctx); 353 354 /* outer hash */ 355 SHA1Init(&sha1ctx); 356 SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad)); 357 SHA1Update(&sha1ctx, md, 20); 358 SHA1Final(md, &sha1ctx); 359} 360 361static int | 352 /* fetch first half of inner hash */ 353 bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx)); 354 355 SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter)); 356 SHA1Final(md, &sha1ctx); 357 358 /* outer hash */ 359 SHA1Init(&sha1ctx); 360 SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad)); 361 SHA1Update(&sha1ctx, md, 20); 362 SHA1Final(md, &sha1ctx); 363} 364 365static int |
362carp_hmac_verify(struct carp_softc *sc, u_int32_t counter[2], | 366carp_hmac_verify(struct carp_softc *sc, uint32_t counter[2], |
363 unsigned char md[20]) 364{ 365 unsigned char md2[20]; 366 | 367 unsigned char md[20]) 368{ 369 unsigned char md2[20]; 370 |
367 CARP_SCLOCK_ASSERT(sc); | 371 CARP_LOCK_ASSERT(sc); |
368 369 carp_hmac_generate(sc, counter, md2); 370 371 return (bcmp(md, md2, sizeof(md2))); 372} 373 | 372 373 carp_hmac_generate(sc, counter, md2); 374 375 return (bcmp(md, md2, sizeof(md2))); 376} 377 |
374static void 375carp_setroute(struct carp_softc *sc, int cmd) 376{ 377 struct ifaddr *ifa; 378 int s; 379 380 if (sc->sc_carpdev) 381 CARP_SCLOCK_ASSERT(sc); 382 383 s = splnet(); 384 TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { 385#ifdef INET 386 if (ifa->ifa_addr->sa_family == AF_INET && 387 sc->sc_carpdev != NULL) { 388 int count = carp_addrcount( 389 (struct carp_if *)sc->sc_carpdev->if_carp, 390 ifatoia(ifa), CARP_COUNT_MASTER); 391 392 if ((cmd == RTM_ADD && count == 1) || 393 (cmd == RTM_DELETE && count == 0)) 394 rtinit(ifa, cmd, RTF_UP | RTF_HOST); 395 } 396#endif 397 } 398 splx(s); 399} 400 401static int 402carp_clone_create(struct if_clone *ifc, int unit, caddr_t params) 403{ 404 405 struct carp_softc *sc; 406 struct ifnet *ifp; 407 408 sc = malloc(sizeof(*sc), M_CARP, M_WAITOK|M_ZERO); 409 ifp = SC2IFP(sc) = if_alloc(IFT_ETHER); 410 if (ifp == NULL) { 411 free(sc, M_CARP); 412 return (ENOSPC); 413 } 414 415 sc->sc_flags_backup = 0; 416 sc->sc_suppress = 0; 417 sc->sc_advbase = CARP_DFLTINTV; 418 sc->sc_vhid = -1; /* required setting */ 419 sc->sc_advskew = 0; 420 sc->sc_init_counter = 1; 421 sc->sc_naddrs = sc->sc_naddrs6 = 0; /* M_ZERO? */ 422#ifdef INET 423 sc->sc_imo.imo_membership = (struct in_multi **)malloc( 424 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, 425 M_WAITOK); 426 sc->sc_imo.imo_mfilters = NULL; 427 sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 428 sc->sc_imo.imo_multicast_vif = -1; 429#endif 430#ifdef INET6 431 sc->sc_im6o.im6o_membership = (struct in6_multi **)malloc( 432 (sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP, 433 M_WAITOK); 434 sc->sc_im6o.im6o_mfilters = NULL; 435 sc->sc_im6o.im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; 436 sc->sc_im6o.im6o_multicast_hlim = CARP_DFLTTL; 437#endif 438 439 callout_init(&sc->sc_ad_tmo, CALLOUT_MPSAFE); 440 callout_init(&sc->sc_md_tmo, CALLOUT_MPSAFE); 441 callout_init(&sc->sc_md6_tmo, CALLOUT_MPSAFE); 442 443 ifp->if_softc = sc; 444 if_initname(ifp, CARP_IFNAME, unit); 445 ifp->if_mtu = ETHERMTU; 446 ifp->if_flags = IFF_LOOPBACK; 447 ifp->if_ioctl = carp_ioctl; 448 ifp->if_output = carp_looutput; 449 ifp->if_start = carp_start; 450 ifp->if_type = IFT_CARP; 451 ifp->if_snd.ifq_maxlen = ifqmaxlen; 452 ifp->if_hdrlen = 0; 453 if_attach(ifp); 454 bpfattach(SC2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 455 mtx_lock(&carp_mtx); 456 LIST_INSERT_HEAD(&carpif_list, sc, sc_next); 457 mtx_unlock(&carp_mtx); 458 return (0); 459} 460 461static void 462carp_clone_destroy(struct ifnet *ifp) 463{ 464 struct carp_softc *sc = ifp->if_softc; 465 466 if (sc->sc_carpdev) 467 CARP_SCLOCK(sc); 468 carpdetach(sc, 1); /* Returns unlocked. */ 469 470 mtx_lock(&carp_mtx); 471 LIST_REMOVE(sc, sc_next); 472 mtx_unlock(&carp_mtx); 473 bpfdetach(ifp); 474 if_detach(ifp); 475 if_free(ifp); 476#ifdef INET 477 free(sc->sc_imo.imo_membership, M_CARP); 478#endif 479#ifdef INET6 480 free(sc->sc_im6o.im6o_membership, M_CARP); 481#endif 482 free(sc, M_CARP); 483} 484 | |
485/* | 378/* |
486 * This function can be called on CARP interface destroy path, 487 * and in case of the removal of the underlying interface as 488 * well. We differentiate these two cases: in case of destruction 489 * of the underlying interface, we do not cleanup our multicast 490 * memberships, since they are already freed. But we purge pointers 491 * to multicast structures, since they are no longer valid, to 492 * avoid panic in future calls to carpdetach(). Also, we do not 493 * release the lock on return, because the function will be 494 * called once more, for another CARP instance on the same 495 * interface. 496 */ 497static void 498carpdetach(struct carp_softc *sc, int unlock) 499{ 500 struct carp_if *cif; 501 502 callout_stop(&sc->sc_ad_tmo); 503 callout_stop(&sc->sc_md_tmo); 504 callout_stop(&sc->sc_md6_tmo); 505 506 if (sc->sc_suppress) 507 carp_suppress_preempt--; 508 sc->sc_suppress = 0; 509 510 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) 511 carp_suppress_preempt--; 512 sc->sc_sendad_errors = 0; 513 514 carp_set_state(sc, INIT); 515 SC2IFP(sc)->if_flags &= ~IFF_UP; 516 carp_setrun(sc, 0); 517#ifdef INET 518 carp_multicast_cleanup(sc, unlock); 519#endif 520#ifdef INET6 521 carp_multicast6_cleanup(sc, unlock); 522#endif 523 524 if (sc->sc_carpdev != NULL) { 525 cif = (struct carp_if *)sc->sc_carpdev->if_carp; 526 CARP_LOCK_ASSERT(cif); 527 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list); 528 if (!--cif->vhif_nvrs) { 529 ifpromisc(sc->sc_carpdev, 0); 530 sc->sc_carpdev->if_carp = NULL; 531 CARP_LOCK_DESTROY(cif); 532 free(cif, M_CARP); 533 } else if (unlock) 534 CARP_UNLOCK(cif); 535 sc->sc_carpdev = NULL; 536 } 537} 538 539/* Detach an interface from the carp. */ 540static void 541carp_ifdetach(void *arg __unused, struct ifnet *ifp) 542{ 543 struct carp_if *cif = (struct carp_if *)ifp->if_carp; 544 struct carp_softc *sc, *nextsc; 545 546 if (cif == NULL) 547 return; 548 549 /* 550 * XXX: At the end of for() cycle the lock will be destroyed. 551 */ 552 CARP_LOCK(cif); 553 for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) { 554 nextsc = TAILQ_NEXT(sc, sc_list); 555 carpdetach(sc, 0); 556 } 557} 558 559/* | |
560 * process input packet. 561 * we have rearranged checks order compared to the rfc, 562 * but it seems more efficient this way or not possible otherwise. 563 */ 564#ifdef INET 565void 566carp_input(struct mbuf *m, int hlen) 567{ 568 struct ip *ip = mtod(m, struct ip *); 569 struct carp_header *ch; 570 int iplen, len; 571 572 CARPSTATS_INC(carps_ipackets); 573 574 if (!carp_opts[CARPCTL_ALLOW]) { 575 m_freem(m); 576 return; 577 } 578 | 379 * process input packet. 380 * we have rearranged checks order compared to the rfc, 381 * but it seems more efficient this way or not possible otherwise. 382 */ 383#ifdef INET 384void 385carp_input(struct mbuf *m, int hlen) 386{ 387 struct ip *ip = mtod(m, struct ip *); 388 struct carp_header *ch; 389 int iplen, len; 390 391 CARPSTATS_INC(carps_ipackets); 392 393 if (!carp_opts[CARPCTL_ALLOW]) { 394 m_freem(m); 395 return; 396 } 397 |
579 /* check if received on a valid carp interface */ 580 if (m->m_pkthdr.rcvif->if_carp == NULL) { 581 CARPSTATS_INC(carps_badif); 582 CARP_DEBUG("carp_input: packet received on non-carp " 583 "interface: %s\n", 584 m->m_pkthdr.rcvif->if_xname); 585 m_freem(m); 586 return; 587 } 588 | |
589 /* verify that the IP TTL is 255. */ 590 if (ip->ip_ttl != CARP_DFLTTL) { 591 CARPSTATS_INC(carps_badttl); | 398 /* verify that the IP TTL is 255. */ 399 if (ip->ip_ttl != CARP_DFLTTL) { 400 CARPSTATS_INC(carps_badttl); |
592 CARP_DEBUG("carp_input: received ttl %d != 255 on %s\n", | 401 CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__, |
593 ip->ip_ttl, 594 m->m_pkthdr.rcvif->if_xname); 595 m_freem(m); 596 return; 597 } 598 599 iplen = ip->ip_hl << 2; 600 601 if (m->m_pkthdr.len < iplen + sizeof(*ch)) { 602 CARPSTATS_INC(carps_badlen); | 402 ip->ip_ttl, 403 m->m_pkthdr.rcvif->if_xname); 404 m_freem(m); 405 return; 406 } 407 408 iplen = ip->ip_hl << 2; 409 410 if (m->m_pkthdr.len < iplen + sizeof(*ch)) { 411 CARPSTATS_INC(carps_badlen); |
603 CARP_DEBUG("carp_input: received len %zd < " 604 "sizeof(struct carp_header) on %s\n", 605 m->m_len - sizeof(struct ip), | 412 CARP_DEBUG("%s: received len %zd < sizeof(struct carp_header) " 413 "on %s\n", __func__, m->m_len - sizeof(struct ip), |
606 m->m_pkthdr.rcvif->if_xname); 607 m_freem(m); 608 return; 609 } 610 611 if (iplen + sizeof(*ch) < m->m_len) { 612 if ((m = m_pullup(m, iplen + sizeof(*ch))) == NULL) { 613 CARPSTATS_INC(carps_hdrops); | 414 m->m_pkthdr.rcvif->if_xname); 415 m_freem(m); 416 return; 417 } 418 419 if (iplen + sizeof(*ch) < m->m_len) { 420 if ((m = m_pullup(m, iplen + sizeof(*ch))) == NULL) { 421 CARPSTATS_INC(carps_hdrops); |
614 CARP_DEBUG("carp_input: pullup failed\n"); | 422 CARP_DEBUG("%s: pullup failed\n", __func__); |
615 return; 616 } 617 ip = mtod(m, struct ip *); 618 } 619 ch = (struct carp_header *)((char *)ip + iplen); 620 621 /* 622 * verify that the received packet length is 623 * equal to the CARP header 624 */ 625 len = iplen + sizeof(*ch); 626 if (len > m->m_pkthdr.len) { 627 CARPSTATS_INC(carps_badlen); | 423 return; 424 } 425 ip = mtod(m, struct ip *); 426 } 427 ch = (struct carp_header *)((char *)ip + iplen); 428 429 /* 430 * verify that the received packet length is 431 * equal to the CARP header 432 */ 433 len = iplen + sizeof(*ch); 434 if (len > m->m_pkthdr.len) { 435 CARPSTATS_INC(carps_badlen); |
628 CARP_DEBUG("carp_input: packet too short %d on %s\n", | 436 CARP_DEBUG("%s: packet too short %d on %s\n", __func__, |
629 m->m_pkthdr.len, 630 m->m_pkthdr.rcvif->if_xname); 631 m_freem(m); 632 return; 633 } 634 635 if ((m = m_pullup(m, len)) == NULL) { 636 CARPSTATS_INC(carps_hdrops); 637 return; 638 } 639 ip = mtod(m, struct ip *); 640 ch = (struct carp_header *)((char *)ip + iplen); 641 642 /* verify the CARP checksum */ 643 m->m_data += iplen; 644 if (carp_cksum(m, len - iplen)) { 645 CARPSTATS_INC(carps_badsum); | 437 m->m_pkthdr.len, 438 m->m_pkthdr.rcvif->if_xname); 439 m_freem(m); 440 return; 441 } 442 443 if ((m = m_pullup(m, len)) == NULL) { 444 CARPSTATS_INC(carps_hdrops); 445 return; 446 } 447 ip = mtod(m, struct ip *); 448 ch = (struct carp_header *)((char *)ip + iplen); 449 450 /* verify the CARP checksum */ 451 m->m_data += iplen; 452 if (carp_cksum(m, len - iplen)) { 453 CARPSTATS_INC(carps_badsum); |
646 CARP_DEBUG("carp_input: checksum failed on %s\n", | 454 CARP_DEBUG("%s: checksum failed on %s\n", __func__, |
647 m->m_pkthdr.rcvif->if_xname); 648 m_freem(m); 649 return; 650 } 651 m->m_data -= iplen; 652 653 carp_input_c(m, ch, AF_INET); 654} --- 13 unchanged lines hidden (view full) --- 668 if (!carp_opts[CARPCTL_ALLOW]) { 669 m_freem(m); 670 return (IPPROTO_DONE); 671 } 672 673 /* check if received on a valid carp interface */ 674 if (m->m_pkthdr.rcvif->if_carp == NULL) { 675 CARPSTATS_INC(carps_badif); | 455 m->m_pkthdr.rcvif->if_xname); 456 m_freem(m); 457 return; 458 } 459 m->m_data -= iplen; 460 461 carp_input_c(m, ch, AF_INET); 462} --- 13 unchanged lines hidden (view full) --- 476 if (!carp_opts[CARPCTL_ALLOW]) { 477 m_freem(m); 478 return (IPPROTO_DONE); 479 } 480 481 /* check if received on a valid carp interface */ 482 if (m->m_pkthdr.rcvif->if_carp == NULL) { 483 CARPSTATS_INC(carps_badif); |
676 CARP_DEBUG("carp6_input: packet received on non-carp " 677 "interface: %s\n", 678 m->m_pkthdr.rcvif->if_xname); | 484 CARP_DEBUG("%s: packet received on non-carp interface: %s\n", 485 __func__, m->m_pkthdr.rcvif->if_xname); |
679 m_freem(m); 680 return (IPPROTO_DONE); 681 } 682 683 /* verify that the IP TTL is 255 */ 684 if (ip6->ip6_hlim != CARP_DFLTTL) { 685 CARPSTATS_INC(carps_badttl); | 486 m_freem(m); 487 return (IPPROTO_DONE); 488 } 489 490 /* verify that the IP TTL is 255 */ 491 if (ip6->ip6_hlim != CARP_DFLTTL) { 492 CARPSTATS_INC(carps_badttl); |
686 CARP_DEBUG("carp6_input: received ttl %d != 255 on %s\n", 687 ip6->ip6_hlim, 688 m->m_pkthdr.rcvif->if_xname); | 493 CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__, 494 ip6->ip6_hlim, m->m_pkthdr.rcvif->if_xname); |
689 m_freem(m); 690 return (IPPROTO_DONE); 691 } 692 693 /* verify that we have a complete carp packet */ 694 len = m->m_len; 695 IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch)); 696 if (ch == NULL) { 697 CARPSTATS_INC(carps_badlen); | 495 m_freem(m); 496 return (IPPROTO_DONE); 497 } 498 499 /* verify that we have a complete carp packet */ 500 len = m->m_len; 501 IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch)); 502 if (ch == NULL) { 503 CARPSTATS_INC(carps_badlen); |
698 CARP_DEBUG("carp6_input: packet size %u too small\n", len); | 504 CARP_DEBUG("%s: packet size %u too small\n", __func__, len); |
699 return (IPPROTO_DONE); 700 } 701 702 703 /* verify the CARP checksum */ 704 m->m_data += *offp; 705 if (carp_cksum(m, sizeof(*ch))) { 706 CARPSTATS_INC(carps_badsum); | 505 return (IPPROTO_DONE); 506 } 507 508 509 /* verify the CARP checksum */ 510 m->m_data += *offp; 511 if (carp_cksum(m, sizeof(*ch))) { 512 CARPSTATS_INC(carps_badsum); |
707 CARP_DEBUG("carp6_input: checksum failed, on %s\n", | 513 CARP_DEBUG("%s: checksum failed, on %s\n", __func__, |
708 m->m_pkthdr.rcvif->if_xname); 709 m_freem(m); 710 return (IPPROTO_DONE); 711 } 712 m->m_data -= *offp; 713 714 carp_input_c(m, ch, AF_INET6); 715 return (IPPROTO_DONE); 716} 717#endif /* INET6 */ 718 719static void 720carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) 721{ 722 struct ifnet *ifp = m->m_pkthdr.rcvif; | 514 m->m_pkthdr.rcvif->if_xname); 515 m_freem(m); 516 return (IPPROTO_DONE); 517 } 518 m->m_data -= *offp; 519 520 carp_input_c(m, ch, AF_INET6); 521 return (IPPROTO_DONE); 522} 523#endif /* INET6 */ 524 525static void 526carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) 527{ 528 struct ifnet *ifp = m->m_pkthdr.rcvif; |
529 struct ifaddr *ifa; |
|
723 struct carp_softc *sc; | 530 struct carp_softc *sc; |
724 u_int64_t tmp_counter; | 531 uint64_t tmp_counter; |
725 struct timeval sc_tv, ch_tv; 726 727 /* verify that the VHID is valid on the receiving interface */ | 532 struct timeval sc_tv, ch_tv; 533 534 /* verify that the VHID is valid on the receiving interface */ |
728 CARP_LOCK(ifp->if_carp); 729 TAILQ_FOREACH(sc, &((struct carp_if *)ifp->if_carp)->vhif_vrs, sc_list) 730 if (sc->sc_vhid == ch->carp_vhid) | 535 IF_ADDR_LOCK(ifp); 536 IFNET_FOREACH_IFA(ifp, ifa) 537 if (ifa->ifa_addr->sa_family == af && 538 ifa->ifa_carp->sc_vhid == ch->carp_vhid) { 539 ifa_ref(ifa); |
731 break; | 540 break; |
541 } 542 IF_ADDR_UNLOCK(ifp); |
|
732 | 543 |
733 if (!sc || !((SC2IFP(sc)->if_flags & IFF_UP) && 734 (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING))) { | 544 if (ifa == NULL) { |
735 CARPSTATS_INC(carps_badvhid); | 545 CARPSTATS_INC(carps_badvhid); |
736 CARP_UNLOCK(ifp->if_carp); | |
737 m_freem(m); 738 return; 739 } 740 | 546 m_freem(m); 547 return; 548 } 549 |
741 getmicrotime(&SC2IFP(sc)->if_lastchange); 742 SC2IFP(sc)->if_ipackets++; 743 SC2IFP(sc)->if_ibytes += m->m_pkthdr.len; 744 745 if (bpf_peers_present(SC2IFP(sc)->if_bpf)) { 746 uint32_t af1 = af; 747#ifdef INET 748 struct ip *ip = mtod(m, struct ip *); 749 750 /* BPF wants net byte order */ 751 if (af == AF_INET) { 752 ip->ip_len = htons(ip->ip_len + (ip->ip_hl << 2)); 753 ip->ip_off = htons(ip->ip_off); 754 } 755#endif 756 bpf_mtap2(SC2IFP(sc)->if_bpf, &af1, sizeof(af1), m); 757 } 758 | |
759 /* verify the CARP version. */ 760 if (ch->carp_version != CARP_VERSION) { 761 CARPSTATS_INC(carps_badver); | 550 /* verify the CARP version. */ 551 if (ch->carp_version != CARP_VERSION) { 552 CARPSTATS_INC(carps_badver); |
762 SC2IFP(sc)->if_ierrors++; 763 CARP_UNLOCK(ifp->if_carp); 764 CARP_DEBUG("%s; invalid version %d\n", 765 SC2IFP(sc)->if_xname, | 553 CARP_DEBUG("%s: invalid version %d\n", ifp->if_xname, |
766 ch->carp_version); | 554 ch->carp_version); |
555 ifa_free(ifa); |
|
767 m_freem(m); 768 return; 769 } 770 | 556 m_freem(m); 557 return; 558 } 559 |
771 /* verify the hash */ | 560 sc = ifa->ifa_carp; 561 CARP_LOCK(sc); 562 ifa_free(ifa); 563 |
772 if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) { 773 CARPSTATS_INC(carps_badauth); | 564 if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) { 565 CARPSTATS_INC(carps_badauth); |
774 SC2IFP(sc)->if_ierrors++; 775 CARP_UNLOCK(ifp->if_carp); 776 CARP_DEBUG("%s: incorrect hash\n", SC2IFP(sc)->if_xname); 777 m_freem(m); 778 return; | 566 CARP_DEBUG("%s: incorrect hash for VHID %u@%s\n", __func__, 567 sc->sc_vhid, ifp->if_xname); 568 goto out; |
779 } 780 781 tmp_counter = ntohl(ch->carp_counter[0]); 782 tmp_counter = tmp_counter<<32; 783 tmp_counter += ntohl(ch->carp_counter[1]); 784 785 /* XXX Replay protection goes here */ 786 --- 14 unchanged lines hidden (view full) --- 801 case MASTER: 802 /* 803 * If we receive an advertisement from a master who's going to 804 * be more frequent than us, go into BACKUP state. 805 */ 806 if (timevalcmp(&sc_tv, &ch_tv, >) || 807 timevalcmp(&sc_tv, &ch_tv, ==)) { 808 callout_stop(&sc->sc_ad_tmo); | 569 } 570 571 tmp_counter = ntohl(ch->carp_counter[0]); 572 tmp_counter = tmp_counter<<32; 573 tmp_counter += ntohl(ch->carp_counter[1]); 574 575 /* XXX Replay protection goes here */ 576 --- 14 unchanged lines hidden (view full) --- 591 case MASTER: 592 /* 593 * If we receive an advertisement from a master who's going to 594 * be more frequent than us, go into BACKUP state. 595 */ 596 if (timevalcmp(&sc_tv, &ch_tv, >) || 597 timevalcmp(&sc_tv, &ch_tv, ==)) { 598 callout_stop(&sc->sc_ad_tmo); |
809 CARP_LOG("%s: MASTER -> BACKUP " 810 "(more frequent advertisement received)\n", 811 SC2IFP(sc)->if_xname); | 599 CARP_LOG("VHID %u@%s: MASTER -> BACKUP " 600 "(more frequent advertisement received)\n", 601 sc->sc_vhid, 602 sc->sc_carpdev->if_xname); |
812 carp_set_state(sc, BACKUP); 813 carp_setrun(sc, 0); | 603 carp_set_state(sc, BACKUP); 604 carp_setrun(sc, 0); |
814 carp_setroute(sc, RTM_DELETE); | 605 carp_delroute(sc); |
815 } 816 break; 817 case BACKUP: 818 /* 819 * If we're pre-empting masters who advertise slower than us, 820 * and this one claims to be slower, treat him as down. 821 */ 822 if (carp_opts[CARPCTL_PREEMPT] && 823 timevalcmp(&sc_tv, &ch_tv, <)) { | 606 } 607 break; 608 case BACKUP: 609 /* 610 * If we're pre-empting masters who advertise slower than us, 611 * and this one claims to be slower, treat him as down. 612 */ 613 if (carp_opts[CARPCTL_PREEMPT] && 614 timevalcmp(&sc_tv, &ch_tv, <)) { |
824 CARP_LOG("%s: BACKUP -> MASTER " | 615 CARP_LOG("VHID %u@%s: BACKUP -> MASTER " |
825 "(preempting a slower master)\n", | 616 "(preempting a slower master)\n", |
826 SC2IFP(sc)->if_xname); | 617 sc->sc_vhid, 618 sc->sc_carpdev->if_xname); |
827 carp_master_down_locked(sc); 828 break; 829 } 830 831 /* 832 * If the master is going to advertise at such a low frequency 833 * that he's guaranteed to time out, we'd might as well just 834 * treat him as timed out now. 835 */ 836 sc_tv.tv_sec = sc->sc_advbase * 3; 837 if (timevalcmp(&sc_tv, &ch_tv, <)) { | 619 carp_master_down_locked(sc); 620 break; 621 } 622 623 /* 624 * If the master is going to advertise at such a low frequency 625 * that he's guaranteed to time out, we'd might as well just 626 * treat him as timed out now. 627 */ 628 sc_tv.tv_sec = sc->sc_advbase * 3; 629 if (timevalcmp(&sc_tv, &ch_tv, <)) { |
838 CARP_LOG("%s: BACKUP -> MASTER " | 630 CARP_LOG("VHID %u@%s: BACKUP -> MASTER " |
839 "(master timed out)\n", | 631 "(master timed out)\n", |
840 SC2IFP(sc)->if_xname); | 632 sc->sc_vhid, 633 sc->sc_carpdev->if_xname); |
841 carp_master_down_locked(sc); 842 break; 843 } 844 845 /* 846 * Otherwise, we reset the counter and wait for the next 847 * advertisement. 848 */ 849 carp_setrun(sc, af); 850 break; 851 } 852 | 634 carp_master_down_locked(sc); 635 break; 636 } 637 638 /* 639 * Otherwise, we reset the counter and wait for the next 640 * advertisement. 641 */ 642 carp_setrun(sc, af); 643 break; 644 } 645 |
853 CARP_UNLOCK(ifp->if_carp); 854 | 646out: 647 CARP_UNLOCK(sc); |
855 m_freem(m); | 648 m_freem(m); |
856 return; | |
857} 858 859static int 860carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch) 861{ 862 struct m_tag *mtag; | 649} 650 651static int 652carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch) 653{ 654 struct m_tag *mtag; |
863 struct ifnet *ifp = SC2IFP(sc); | |
864 865 if (sc->sc_init_counter) { 866 /* this could also be seconds since unix epoch */ 867 sc->sc_counter = arc4random(); 868 sc->sc_counter = sc->sc_counter << 32; 869 sc->sc_counter += arc4random(); 870 } else 871 sc->sc_counter++; 872 873 ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff); 874 ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff); 875 876 carp_hmac_generate(sc, ch->carp_counter, ch->carp_md); 877 878 /* Tag packet for carp_output */ | 655 656 if (sc->sc_init_counter) { 657 /* this could also be seconds since unix epoch */ 658 sc->sc_counter = arc4random(); 659 sc->sc_counter = sc->sc_counter << 32; 660 sc->sc_counter += arc4random(); 661 } else 662 sc->sc_counter++; 663 664 ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff); 665 ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff); 666 667 carp_hmac_generate(sc, ch->carp_counter, ch->carp_md); 668 669 /* Tag packet for carp_output */ |
879 mtag = m_tag_get(PACKET_TAG_CARP, sizeof(struct ifnet *), M_NOWAIT); 880 if (mtag == NULL) { | 670 if ((mtag = m_tag_get(PACKET_TAG_CARP, sizeof(struct carp_softc *), 671 M_NOWAIT)) == NULL) { |
881 m_freem(m); | 672 m_freem(m); |
882 SC2IFP(sc)->if_oerrors++; | 673 CARPSTATS_INC(carps_onomem); |
883 return (ENOMEM); 884 } | 674 return (ENOMEM); 675 } |
885 bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *)); | 676 bcopy(&sc, (caddr_t)(mtag + 1), sizeof(struct carp_softc *)); |
886 m_tag_prepend(m, mtag); 887 888 return (0); 889} 890 891static void | 677 m_tag_prepend(m, mtag); 678 679 return (0); 680} 681 682static void |
892carp_send_ad_all(void) | 683carp_send_ad_all(struct carp_softc *badsc) |
893{ 894 struct carp_softc *sc; 895 | 684{ 685 struct carp_softc *sc; 686 |
687 /* 688 * Avoid LOR and recursive call to carp_send_ad_locked(). 689 */ 690 CARP_UNLOCK(badsc); 691 |
|
896 mtx_lock(&carp_mtx); | 692 mtx_lock(&carp_mtx); |
897 LIST_FOREACH(sc, &carpif_list, sc_next) { 898 if (sc->sc_carpdev == NULL) 899 continue; 900 CARP_SCLOCK(sc); 901 if ((SC2IFP(sc)->if_flags & IFF_UP) && 902 (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING) && 903 sc->sc_state == MASTER) | 693 LIST_FOREACH(sc, &carp_list, sc_next) 694 if (sc != badsc && sc->sc_state == MASTER) { 695 CARP_LOCK(sc); |
904 carp_send_ad_locked(sc); | 696 carp_send_ad_locked(sc); |
905 CARP_SCUNLOCK(sc); 906 } | 697 CARP_UNLOCK(sc); 698 } |
907 mtx_unlock(&carp_mtx); | 699 mtx_unlock(&carp_mtx); |
700 701 CARP_LOCK(badsc); |
|
908} 909 910static void 911carp_send_ad(void *v) 912{ 913 struct carp_softc *sc = v; 914 | 702} 703 704static void 705carp_send_ad(void *v) 706{ 707 struct carp_softc *sc = v; 708 |
915 CARP_SCLOCK(sc); | 709 CARP_LOCK_ASSERT(sc); |
916 carp_send_ad_locked(sc); | 710 carp_send_ad_locked(sc); |
917 CARP_SCUNLOCK(sc); | 711 CARP_UNLOCK(sc); |
918} 919 920static void 921carp_send_ad_locked(struct carp_softc *sc) 922{ 923 struct carp_header ch; 924 struct timeval tv; | 712} 713 714static void 715carp_send_ad_locked(struct carp_softc *sc) 716{ 717 struct carp_header ch; 718 struct timeval tv; |
719 struct sockaddr sa; 720 struct ifaddr *ifa; |
|
925 struct carp_header *ch_ptr; 926 struct mbuf *m; | 721 struct carp_header *ch_ptr; 722 struct mbuf *m; |
927 int len, advbase, advskew; | 723 int len, advskew; |
928 | 724 |
929 CARP_SCLOCK_ASSERT(sc); | 725 CARP_LOCK_ASSERT(sc); |
930 | 726 |
931 /* bow out if we've lost our UPness or RUNNINGuiness */ 932 if (!((SC2IFP(sc)->if_flags & IFF_UP) && 933 (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING))) { 934 advbase = 255; 935 advskew = 255; 936 } else { 937 advbase = sc->sc_advbase; 938 if (!carp_suppress_preempt || sc->sc_advskew > 240) 939 advskew = sc->sc_advskew; 940 else 941 advskew = 240; 942 tv.tv_sec = advbase; 943 tv.tv_usec = advskew * 1000000 / 256; 944 } | 727 if (!carp_suppress_preempt || sc->sc_advskew > 240) 728 advskew = sc->sc_advskew; 729 else 730 advskew = 240; 731 tv.tv_sec = sc->sc_advbase; 732 tv.tv_usec = advskew * 1000000 / 256; |
945 946 ch.carp_version = CARP_VERSION; 947 ch.carp_type = CARP_ADVERTISEMENT; 948 ch.carp_vhid = sc->sc_vhid; | 733 734 ch.carp_version = CARP_VERSION; 735 ch.carp_type = CARP_ADVERTISEMENT; 736 ch.carp_vhid = sc->sc_vhid; |
949 ch.carp_advbase = advbase; | 737 ch.carp_advbase = sc->sc_advbase; |
950 ch.carp_advskew = advskew; 951 ch.carp_authlen = 7; /* XXX DEFINE */ 952 ch.carp_pad1 = 0; /* must be zero */ 953 ch.carp_cksum = 0; 954 | 738 ch.carp_advskew = advskew; 739 ch.carp_authlen = 7; /* XXX DEFINE */ 740 ch.carp_pad1 = 0; /* must be zero */ 741 ch.carp_cksum = 0; 742 |
743 /* XXXGL: OpenBSD picks first ifaddr with needed family. */ 744 |
|
955#ifdef INET | 745#ifdef INET |
956 if (sc->sc_ia) { | 746 if (sc->sc_naddrs) { |
957 struct ip *ip; 958 | 747 struct ip *ip; 748 |
959 MGETHDR(m, M_DONTWAIT, MT_HEADER); | 749 MGETHDR(m, M_NOWAIT, MT_HEADER); |
960 if (m == NULL) { | 750 if (m == NULL) { |
961 SC2IFP(sc)->if_oerrors++; | |
962 CARPSTATS_INC(carps_onomem); 963 /* XXX maybe less ? */ | 751 CARPSTATS_INC(carps_onomem); 752 /* XXX maybe less ? */ |
964 if (advbase != 255 || advskew != 255) 965 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 966 carp_send_ad, sc); | 753 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 754 carp_send_ad, sc); |
967 return; 968 } 969 len = sizeof(*ip) + sizeof(ch); 970 m->m_pkthdr.len = len; 971 m->m_pkthdr.rcvif = NULL; 972 m->m_len = len; 973 MH_ALIGN(m, m->m_len); 974 m->m_flags |= M_MCAST; 975 ip = mtod(m, struct ip *); 976 ip->ip_v = IPVERSION; 977 ip->ip_hl = sizeof(*ip) >> 2; 978 ip->ip_tos = IPTOS_LOWDELAY; 979 ip->ip_len = len; 980 ip->ip_id = ip_newid(); 981 ip->ip_off = IP_DF; 982 ip->ip_ttl = CARP_DFLTTL; 983 ip->ip_p = IPPROTO_CARP; 984 ip->ip_sum = 0; | 755 return; 756 } 757 len = sizeof(*ip) + sizeof(ch); 758 m->m_pkthdr.len = len; 759 m->m_pkthdr.rcvif = NULL; 760 m->m_len = len; 761 MH_ALIGN(m, m->m_len); 762 m->m_flags |= M_MCAST; 763 ip = mtod(m, struct ip *); 764 ip->ip_v = IPVERSION; 765 ip->ip_hl = sizeof(*ip) >> 2; 766 ip->ip_tos = IPTOS_LOWDELAY; 767 ip->ip_len = len; 768 ip->ip_id = ip_newid(); 769 ip->ip_off = IP_DF; 770 ip->ip_ttl = CARP_DFLTTL; 771 ip->ip_p = IPPROTO_CARP; 772 ip->ip_sum = 0; |
985 ip->ip_src.s_addr = sc->sc_ia->ia_addr.sin_addr.s_addr; | 773 774 bzero(&sa, sizeof(sa)); 775 sa.sa_family = AF_INET; 776 ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev); 777 if (ifa != NULL) { 778 ip->ip_src.s_addr = 779 ifatoia(ifa)->ia_addr.sin_addr.s_addr; 780 ifa_free(ifa); 781 } else 782 ip->ip_src.s_addr = 0; |
986 ip->ip_dst.s_addr = htonl(INADDR_CARP_GROUP); 987 988 ch_ptr = (struct carp_header *)(&ip[1]); 989 bcopy(&ch, ch_ptr, sizeof(ch)); 990 if (carp_prepare_ad(m, sc, ch_ptr)) 991 return; 992 993 m->m_data += sizeof(*ip); 994 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip)); 995 m->m_data -= sizeof(*ip); 996 | 783 ip->ip_dst.s_addr = htonl(INADDR_CARP_GROUP); 784 785 ch_ptr = (struct carp_header *)(&ip[1]); 786 bcopy(&ch, ch_ptr, sizeof(ch)); 787 if (carp_prepare_ad(m, sc, ch_ptr)) 788 return; 789 790 m->m_data += sizeof(*ip); 791 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip)); 792 m->m_data -= sizeof(*ip); 793 |
997 getmicrotime(&SC2IFP(sc)->if_lastchange); 998 SC2IFP(sc)->if_opackets++; 999 SC2IFP(sc)->if_obytes += len; | |
1000 CARPSTATS_INC(carps_opackets); 1001 | 794 CARPSTATS_INC(carps_opackets); 795 |
1002 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) { 1003 SC2IFP(sc)->if_oerrors++; | 796 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, 797 &sc->sc_carpdev->if_carp->cif_imo, NULL)) { |
1004 if (sc->sc_sendad_errors < INT_MAX) 1005 sc->sc_sendad_errors++; 1006 if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) { 1007 carp_suppress_preempt++; | 798 if (sc->sc_sendad_errors < INT_MAX) 799 sc->sc_sendad_errors++; 800 if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) { 801 carp_suppress_preempt++; |
1008 if (carp_suppress_preempt == 1) { 1009 CARP_SCUNLOCK(sc); 1010 carp_send_ad_all(); 1011 CARP_SCLOCK(sc); 1012 } | 802 if (carp_suppress_preempt == 1) 803 carp_send_ad_all(sc); |
1013 } 1014 sc->sc_sendad_success = 0; 1015 } else { 1016 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) { 1017 if (++sc->sc_sendad_success >= 1018 CARP_SENDAD_MIN_SUCCESS) { 1019 carp_suppress_preempt--; 1020 sc->sc_sendad_errors = 0; 1021 } 1022 } else 1023 sc->sc_sendad_errors = 0; 1024 } 1025 } 1026#endif /* INET */ 1027#ifdef INET6 | 804 } 805 sc->sc_sendad_success = 0; 806 } else { 807 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) { 808 if (++sc->sc_sendad_success >= 809 CARP_SENDAD_MIN_SUCCESS) { 810 carp_suppress_preempt--; 811 sc->sc_sendad_errors = 0; 812 } 813 } else 814 sc->sc_sendad_errors = 0; 815 } 816 } 817#endif /* INET */ 818#ifdef INET6 |
1028 if (sc->sc_ia6) { | 819 if (sc->sc_naddrs6) { |
1029 struct ip6_hdr *ip6; 1030 | 820 struct ip6_hdr *ip6; 821 |
1031 MGETHDR(m, M_DONTWAIT, MT_HEADER); | 822 MGETHDR(m, M_NOWAIT, MT_HEADER); |
1032 if (m == NULL) { | 823 if (m == NULL) { |
1033 SC2IFP(sc)->if_oerrors++; | |
1034 CARPSTATS_INC(carps_onomem); 1035 /* XXX maybe less ? */ | 824 CARPSTATS_INC(carps_onomem); 825 /* XXX maybe less ? */ |
1036 if (advbase != 255 || advskew != 255) 1037 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 1038 carp_send_ad, sc); | 826 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 827 carp_send_ad, sc); |
1039 return; 1040 } 1041 len = sizeof(*ip6) + sizeof(ch); 1042 m->m_pkthdr.len = len; 1043 m->m_pkthdr.rcvif = NULL; 1044 m->m_len = len; 1045 MH_ALIGN(m, m->m_len); 1046 m->m_flags |= M_MCAST; 1047 ip6 = mtod(m, struct ip6_hdr *); 1048 bzero(ip6, sizeof(*ip6)); 1049 ip6->ip6_vfc |= IPV6_VERSION; 1050 ip6->ip6_hlim = CARP_DFLTTL; 1051 ip6->ip6_nxt = IPPROTO_CARP; | 828 return; 829 } 830 len = sizeof(*ip6) + sizeof(ch); 831 m->m_pkthdr.len = len; 832 m->m_pkthdr.rcvif = NULL; 833 m->m_len = len; 834 MH_ALIGN(m, m->m_len); 835 m->m_flags |= M_MCAST; 836 ip6 = mtod(m, struct ip6_hdr *); 837 bzero(ip6, sizeof(*ip6)); 838 ip6->ip6_vfc |= IPV6_VERSION; 839 ip6->ip6_hlim = CARP_DFLTTL; 840 ip6->ip6_nxt = IPPROTO_CARP; |
1052 bcopy(&sc->sc_ia6->ia_addr.sin6_addr, &ip6->ip6_src, 1053 sizeof(struct in6_addr)); 1054 /* set the multicast destination */ | 841 bzero(&sa, sizeof(sa)); |
1055 | 842 |
843 /* set the source address */ 844 sa.sa_family = AF_INET6; 845 ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev); 846 if (ifa != NULL) { 847 bcopy(IFA_IN6(ifa), &ip6->ip6_src, 848 sizeof(struct in6_addr)); 849 ifa_free(ifa); 850 } else 851 /* This should never happen with IPv6. */ 852 bzero(&ip6->ip6_src, sizeof(struct in6_addr)); 853 854 /* Set the multicast destination. */ |
|
1056 ip6->ip6_dst.s6_addr16[0] = htons(0xff02); 1057 ip6->ip6_dst.s6_addr8[15] = 0x12; 1058 if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) { | 855 ip6->ip6_dst.s6_addr16[0] = htons(0xff02); 856 ip6->ip6_dst.s6_addr8[15] = 0x12; 857 if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) { |
1059 SC2IFP(sc)->if_oerrors++; | |
1060 m_freem(m); 1061 CARP_DEBUG("%s: in6_setscope failed\n", __func__); 1062 return; 1063 } 1064 1065 ch_ptr = (struct carp_header *)(&ip6[1]); 1066 bcopy(&ch, ch_ptr, sizeof(ch)); 1067 if (carp_prepare_ad(m, sc, ch_ptr)) 1068 return; 1069 1070 m->m_data += sizeof(*ip6); 1071 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip6)); 1072 m->m_data -= sizeof(*ip6); 1073 | 858 m_freem(m); 859 CARP_DEBUG("%s: in6_setscope failed\n", __func__); 860 return; 861 } 862 863 ch_ptr = (struct carp_header *)(&ip6[1]); 864 bcopy(&ch, ch_ptr, sizeof(ch)); 865 if (carp_prepare_ad(m, sc, ch_ptr)) 866 return; 867 868 m->m_data += sizeof(*ip6); 869 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip6)); 870 m->m_data -= sizeof(*ip6); 871 |
1074 getmicrotime(&SC2IFP(sc)->if_lastchange); 1075 SC2IFP(sc)->if_opackets++; 1076 SC2IFP(sc)->if_obytes += len; | |
1077 CARPSTATS_INC(carps_opackets6); 1078 | 872 CARPSTATS_INC(carps_opackets6); 873 |
1079 if (ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL)) { 1080 SC2IFP(sc)->if_oerrors++; | 874 if (ip6_output(m, NULL, NULL, 0, 875 &sc->sc_carpdev->if_carp->cif_im6o, NULL, NULL)) { |
1081 if (sc->sc_sendad_errors < INT_MAX) 1082 sc->sc_sendad_errors++; 1083 if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) { 1084 carp_suppress_preempt++; | 876 if (sc->sc_sendad_errors < INT_MAX) 877 sc->sc_sendad_errors++; 878 if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) { 879 carp_suppress_preempt++; |
1085 if (carp_suppress_preempt == 1) { 1086 CARP_SCUNLOCK(sc); 1087 carp_send_ad_all(); 1088 CARP_SCLOCK(sc); 1089 } | 880 if (carp_suppress_preempt == 1) 881 carp_send_ad_all(sc); |
1090 } 1091 sc->sc_sendad_success = 0; 1092 } else { 1093 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) { 1094 if (++sc->sc_sendad_success >= 1095 CARP_SENDAD_MIN_SUCCESS) { 1096 carp_suppress_preempt--; 1097 sc->sc_sendad_errors = 0; 1098 } 1099 } else 1100 sc->sc_sendad_errors = 0; 1101 } 1102 } 1103#endif /* INET6 */ 1104 | 882 } 883 sc->sc_sendad_success = 0; 884 } else { 885 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) { 886 if (++sc->sc_sendad_success >= 887 CARP_SENDAD_MIN_SUCCESS) { 888 carp_suppress_preempt--; 889 sc->sc_sendad_errors = 0; 890 } 891 } else 892 sc->sc_sendad_errors = 0; 893 } 894 } 895#endif /* INET6 */ 896 |
1105 if (advbase != 255 || advskew != 255) 1106 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 1107 carp_send_ad, sc); | 897 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), carp_send_ad, sc); 898} |
1108 | 899 |
900static void 901carp_addroute(struct carp_softc *sc) 902{ 903 struct ifaddr *ifa; 904 905 CARP_FOREACH_IFA(sc, ifa) 906 switch (ifa->ifa_addr->sa_family) { 907#ifdef INET 908 case AF_INET: 909 in_addprefix(ifatoia(ifa), RTF_UP); 910 ifa_add_loopback_route(ifa, 911 (struct sockaddr *)&ifatoia(ifa)->ia_addr); 912 break; 913#endif 914#ifdef INET6 915 case AF_INET6: 916 ifa_add_loopback_route(ifa, 917 (struct sockaddr *)&ifatoia6(ifa)->ia_addr); 918 in6_ifaddloop(ifa); 919 break; 920#endif 921 } |
|
1109} 1110 | 922} 923 |
924static void 925carp_delroute(struct carp_softc *sc) 926{ 927 struct ifaddr *ifa; 928 929 CARP_FOREACH_IFA(sc, ifa) 930 switch (ifa->ifa_addr->sa_family) { |
|
1111#ifdef INET | 931#ifdef INET |
932 case AF_INET: 933 ifa_del_loopback_route(ifa, 934 (struct sockaddr *)&ifatoia(ifa)->ia_addr); 935 in_scrubprefix(ifatoia(ifa), LLE_STATIC); 936 break; 937#endif 938#ifdef INET6 939 case AF_INET6: 940 ifa_del_loopback_route(ifa, 941 (struct sockaddr *)&ifatoia6(ifa)->ia_addr); 942 in6_ifremloop(ifa); 943 break; 944#endif 945 } 946} 947 948#ifdef INET |
|
1112/* 1113 * Broadcast a gratuitous ARP request containing 1114 * the virtual router MAC address for each IP address 1115 * associated with the virtual router. 1116 */ 1117static void 1118carp_send_arp(struct carp_softc *sc) 1119{ 1120 struct ifaddr *ifa; 1121 | 949/* 950 * Broadcast a gratuitous ARP request containing 951 * the virtual router MAC address for each IP address 952 * associated with the virtual router. 953 */ 954static void 955carp_send_arp(struct carp_softc *sc) 956{ 957 struct ifaddr *ifa; 958 |
1122 TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { | 959 CARP_FOREACH_IFA(sc, ifa) 960 if (ifa->ifa_addr->sa_family == AF_INET) 961 arp_ifinit2(sc->sc_carpdev, ifa, LLADDR(&sc->sc_addr)); 962} |
1123 | 963 |
1124 if (ifa->ifa_addr->sa_family != AF_INET) 1125 continue; | 964int 965carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr) 966{ 967 struct carp_softc *sc = ifa->ifa_carp; |
1126 | 968 |
1127/* arprequest(sc->sc_carpdev, &in, &in, IF_LLADDR(sc->sc_ifp)); */ 1128 arp_ifinit2(sc->sc_carpdev, ifa, IF_LLADDR(sc->sc_ifp)); 1129 1130 DELAY(1000); /* XXX */ | 969 if (sc->sc_state == MASTER) { 970 *enaddr = LLADDR(&sc->sc_addr); 971 return (1); |
1131 } | 972 } |
973 974 return (0); |
|
1132} 1133#endif 1134 1135#ifdef INET6 1136static void 1137carp_send_na(struct carp_softc *sc) 1138{ | 975} 976#endif 977 978#ifdef INET6 979static void 980carp_send_na(struct carp_softc *sc) 981{ |
982 static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
|
1139 struct ifaddr *ifa; 1140 struct in6_addr *in6; | 983 struct ifaddr *ifa; 984 struct in6_addr *in6; |
1141 static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; | |
1142 | 985 |
1143 TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { 1144 | 986 CARP_FOREACH_IFA(sc, ifa) { |
1145 if (ifa->ifa_addr->sa_family != AF_INET6) 1146 continue; 1147 | 987 if (ifa->ifa_addr->sa_family != AF_INET6) 988 continue; 989 |
1148 in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; | 990 in6 = IFA_IN6(ifa); |
1149 nd6_na_output(sc->sc_carpdev, &mcast, in6, 1150 ND_NA_FLAG_OVERRIDE, 1, NULL); 1151 DELAY(1000); /* XXX */ 1152 } 1153} | 991 nd6_na_output(sc->sc_carpdev, &mcast, in6, 992 ND_NA_FLAG_OVERRIDE, 1, NULL); 993 DELAY(1000); /* XXX */ 994 } 995} |
1154#endif /* INET6 */ | |
1155 | 996 |
1156#ifdef INET 1157static int 1158carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type) 1159{ 1160 struct carp_softc *vh; 1161 struct ifaddr *ifa; 1162 int count = 0; 1163 1164 CARP_LOCK_ASSERT(cif); 1165 1166 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1167 if ((type == CARP_COUNT_RUNNING && 1168 (SC2IFP(vh)->if_flags & IFF_UP) && 1169 (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING)) || 1170 (type == CARP_COUNT_MASTER && vh->sc_state == MASTER)) { 1171 IF_ADDR_LOCK(SC2IFP(vh)); 1172 TAILQ_FOREACH(ifa, &SC2IFP(vh)->if_addrlist, 1173 ifa_list) { 1174 if (ifa->ifa_addr->sa_family == AF_INET && 1175 ia->ia_addr.sin_addr.s_addr == 1176 ifatoia(ifa)->ia_addr.sin_addr.s_addr) 1177 count++; 1178 } 1179 IF_ADDR_UNLOCK(SC2IFP(vh)); 1180 } 1181 } 1182 return (count); 1183} 1184 1185int 1186carp_iamatch(struct ifnet *ifp, struct in_ifaddr *ia, 1187 struct in_addr *isaddr, u_int8_t **enaddr) 1188{ 1189 struct carp_if *cif; 1190 struct carp_softc *vh; 1191 int index, count = 0; 1192 struct ifaddr *ifa; 1193 1194 cif = ifp->if_carp; 1195 CARP_LOCK(cif); 1196 1197 if (carp_opts[CARPCTL_ARPBALANCE]) { 1198 /* 1199 * XXX proof of concept implementation. 1200 * We use the source ip to decide which virtual host should 1201 * handle the request. If we're master of that virtual host, 1202 * then we respond, otherwise, just drop the arp packet on 1203 * the floor. 1204 */ 1205 count = carp_addrcount(cif, ia, CARP_COUNT_RUNNING); 1206 if (count == 0) { 1207 /* should never reach this */ 1208 CARP_UNLOCK(cif); 1209 return (0); 1210 } 1211 1212 /* this should be a hash, like pf_hash() */ 1213 index = ntohl(isaddr->s_addr) % count; 1214 count = 0; 1215 1216 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1217 if ((SC2IFP(vh)->if_flags & IFF_UP) && 1218 (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING)) { 1219 IF_ADDR_LOCK(SC2IFP(vh)); 1220 TAILQ_FOREACH(ifa, &SC2IFP(vh)->if_addrlist, 1221 ifa_list) { 1222 if (ifa->ifa_addr->sa_family == 1223 AF_INET && 1224 ia->ia_addr.sin_addr.s_addr == 1225 ifatoia(ifa)->ia_addr.sin_addr.s_addr) { 1226 if (count == index) { 1227 if (vh->sc_state == 1228 MASTER) { 1229 *enaddr = IF_LLADDR(vh->sc_ifp); 1230 IF_ADDR_UNLOCK(SC2IFP(vh)); 1231 CARP_UNLOCK(cif); 1232 return (1); 1233 } else { 1234 IF_ADDR_UNLOCK(SC2IFP(vh)); 1235 CARP_UNLOCK(cif); 1236 return (0); 1237 } 1238 } 1239 count++; 1240 } 1241 } 1242 IF_ADDR_UNLOCK(SC2IFP(vh)); 1243 } 1244 } 1245 } else { 1246 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1247 if ((SC2IFP(vh)->if_flags & IFF_UP) && 1248 (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING) && 1249 ia->ia_ifp == SC2IFP(vh) && 1250 vh->sc_state == MASTER) { 1251 *enaddr = IF_LLADDR(vh->sc_ifp); 1252 CARP_UNLOCK(cif); 1253 return (1); 1254 } 1255 } 1256 } 1257 CARP_UNLOCK(cif); 1258 return (0); 1259} 1260#endif 1261 1262#ifdef INET6 | |
1263struct ifaddr * 1264carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) 1265{ | 997struct ifaddr * 998carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) 999{ |
1266 struct carp_if *cif; 1267 struct carp_softc *vh; | |
1268 struct ifaddr *ifa; 1269 | 1000 struct ifaddr *ifa; 1001 |
1270 cif = ifp->if_carp; 1271 CARP_LOCK(cif); 1272 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1273 IF_ADDR_LOCK(SC2IFP(vh)); 1274 TAILQ_FOREACH(ifa, &SC2IFP(vh)->if_addrlist, ifa_list) { 1275 if (IN6_ARE_ADDR_EQUAL(taddr, 1276 &ifatoia6(ifa)->ia_addr.sin6_addr) && 1277 (SC2IFP(vh)->if_flags & IFF_UP) && 1278 (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING) && 1279 vh->sc_state == MASTER) { 1280 ifa_ref(ifa); 1281 IF_ADDR_UNLOCK(SC2IFP(vh)); 1282 CARP_UNLOCK(cif); 1283 return (ifa); 1284 } | 1002 IF_ADDR_LOCK(ifp); 1003 IFNET_FOREACH_IFA(ifp, ifa) 1004 if (ifa->ifa_addr->sa_family == AF_INET6 && 1005 ifa->ifa_carp->sc_state == MASTER && 1006 IN6_ARE_ADDR_EQUAL(taddr, IFA_IN6(ifa))) { 1007 ifa_ref(ifa); 1008 IF_ADDR_UNLOCK(ifp); 1009 return (ifa); |
1285 } | 1010 } |
1286 IF_ADDR_UNLOCK(SC2IFP(vh)); 1287 } 1288 CARP_UNLOCK(cif); 1289 | 1011 IF_ADDR_UNLOCK(ifp); 1012 |
1290 return (NULL); 1291} 1292 1293caddr_t 1294carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) 1295{ | 1013 return (NULL); 1014} 1015 1016caddr_t 1017carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) 1018{ |
1296 struct m_tag *mtag; 1297 struct carp_if *cif; 1298 struct carp_softc *sc; | |
1299 struct ifaddr *ifa; 1300 | 1019 struct ifaddr *ifa; 1020 |
1301 cif = ifp->if_carp; 1302 CARP_LOCK(cif); 1303 TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) { 1304 IF_ADDR_LOCK(SC2IFP(sc)); 1305 TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) { 1306 if (IN6_ARE_ADDR_EQUAL(taddr, 1307 &ifatoia6(ifa)->ia_addr.sin6_addr) && 1308 (SC2IFP(sc)->if_flags & IFF_UP) && 1309 (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING)) { 1310 struct ifnet *ifp = SC2IFP(sc); 1311 mtag = m_tag_get(PACKET_TAG_CARP, 1312 sizeof(struct ifnet *), M_NOWAIT); 1313 if (mtag == NULL) { 1314 /* better a bit than nothing */ 1315 IF_ADDR_UNLOCK(SC2IFP(sc)); 1316 CARP_UNLOCK(cif); 1317 return (IF_LLADDR(sc->sc_ifp)); 1318 } 1319 bcopy(&ifp, (caddr_t)(mtag + 1), 1320 sizeof(struct ifnet *)); 1321 m_tag_prepend(m, mtag); | 1021 IF_ADDR_LOCK(ifp); 1022 IFNET_FOREACH_IFA(ifp, ifa) 1023 if (ifa->ifa_addr->sa_family == AF_INET6 && 1024 IN6_ARE_ADDR_EQUAL(taddr, IFA_IN6(ifa))) { 1025 struct carp_softc *sc = ifa->ifa_carp; 1026 struct m_tag *mtag; |
1322 | 1027 |
1323 IF_ADDR_UNLOCK(SC2IFP(sc)); 1324 CARP_UNLOCK(cif); 1325 return (IF_LLADDR(sc->sc_ifp)); 1326 } | 1028 IF_ADDR_UNLOCK(ifp); 1029 1030 mtag = m_tag_get(PACKET_TAG_CARP, 1031 sizeof(struct ifnet *), M_NOWAIT); 1032 if (mtag == NULL) 1033 /* Better a bit than nothing. */ 1034 return (LLADDR(&sc->sc_addr)); 1035 1036 bcopy(&ifp, (caddr_t)(mtag + 1), 1037 sizeof(struct ifnet *)); 1038 m_tag_prepend(m, mtag); 1039 1040 return (LLADDR(&sc->sc_addr)); |
1327 } | 1041 } |
1328 IF_ADDR_UNLOCK(SC2IFP(sc)); 1329 } 1330 CARP_UNLOCK(cif); | 1042 IF_ADDR_UNLOCK(ifp); |
1331 1332 return (NULL); 1333} | 1043 1044 return (NULL); 1045} |
1334#endif | 1046#endif /* INET6 */ |
1335 | 1047 |
1336struct ifnet * | 1048int |
1337carp_forus(struct ifnet *ifp, u_char *dhost) 1338{ | 1049carp_forus(struct ifnet *ifp, u_char *dhost) 1050{ |
1339 struct carp_if *cif; 1340 struct carp_softc *vh; 1341 u_int8_t *ena = dhost; | 1051 struct carp_softc *sc; 1052 uint8_t *ena = dhost; |
1342 1343 if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1) | 1053 1054 if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1) |
1344 return (NULL); | 1055 return (0); |
1345 | 1056 |
1346 cif = ifp->if_carp; 1347 CARP_LOCK(cif); 1348 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) 1349 if ((SC2IFP(vh)->if_flags & IFF_UP) && 1350 (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING) && 1351 vh->sc_state == MASTER && 1352 !bcmp(dhost, IF_LLADDR(vh->sc_ifp), ETHER_ADDR_LEN)) { 1353 CARP_UNLOCK(cif); 1354 return (SC2IFP(vh)); | 1057 CIF_LOCK(ifp->if_carp); 1058 IFNET_FOREACH_CARP(ifp, sc) { 1059 CARP_LOCK(sc); 1060 if (sc->sc_state == MASTER && !bcmp(dhost, LLADDR(&sc->sc_addr), 1061 ETHER_ADDR_LEN)) { 1062 CARP_UNLOCK(sc); 1063 CIF_UNLOCK(ifp->if_carp); 1064 return (1); |
1355 } | 1065 } |
1066 CARP_UNLOCK(sc); 1067 } 1068 CIF_UNLOCK(ifp->if_carp); |
|
1356 | 1069 |
1357 CARP_UNLOCK(cif); 1358 return (NULL); | 1070 return (0); |
1359} 1360 1361static void 1362carp_master_down(void *v) 1363{ 1364 struct carp_softc *sc = v; 1365 | 1071} 1072 1073static void 1074carp_master_down(void *v) 1075{ 1076 struct carp_softc *sc = v; 1077 |
1366 CARP_SCLOCK(sc); 1367 carp_master_down_locked(sc); 1368 CARP_SCUNLOCK(sc); | 1078 CARP_LOCK_ASSERT(sc); 1079 1080 if (sc->sc_state == BACKUP) { 1081 CARP_LOG("VHID %u@%s: BACKUP -> MASTER (preempting)\n", 1082 sc->sc_vhid, 1083 sc->sc_carpdev->if_xname); 1084 carp_master_down_locked(sc); 1085 } 1086 1087 CARP_UNLOCK(sc); |
1369} 1370 1371static void 1372carp_master_down_locked(struct carp_softc *sc) 1373{ | 1088} 1089 1090static void 1091carp_master_down_locked(struct carp_softc *sc) 1092{ |
1374 if (sc->sc_carpdev) 1375 CARP_SCLOCK_ASSERT(sc); | |
1376 | 1093 |
1094 CARP_LOCK_ASSERT(sc); 1095 |
|
1377 switch (sc->sc_state) { | 1096 switch (sc->sc_state) { |
1378 case INIT: 1379 printf("%s: master_down event in INIT state\n", 1380 SC2IFP(sc)->if_xname); 1381 break; 1382 case MASTER: 1383 break; | |
1384 case BACKUP: 1385 carp_set_state(sc, MASTER); 1386 carp_send_ad_locked(sc); 1387#ifdef INET 1388 carp_send_arp(sc); 1389#endif 1390#ifdef INET6 1391 carp_send_na(sc); | 1097 case BACKUP: 1098 carp_set_state(sc, MASTER); 1099 carp_send_ad_locked(sc); 1100#ifdef INET 1101 carp_send_arp(sc); 1102#endif 1103#ifdef INET6 1104 carp_send_na(sc); |
1392#endif /* INET6 */ | 1105#endif |
1393 carp_setrun(sc, 0); | 1106 carp_setrun(sc, 0); |
1394 carp_setroute(sc, RTM_ADD); | 1107 carp_addroute(sc); |
1395 break; | 1108 break; |
1109 case INIT: 1110 case MASTER: 1111#ifdef INVARIANTS 1112 panic("carp: VHID %u@%s: master_down event in %s state\n", 1113 sc->sc_vhid, 1114 sc->sc_carpdev->if_xname, 1115 sc->sc_state ? "MASTER" : "INIT"); 1116#endif 1117 break; |
|
1396 } 1397} 1398 1399/* 1400 * When in backup state, af indicates whether to reset the master down timer 1401 * for v4 or v6. If it's set to zero, reset the ones which are already pending. 1402 */ 1403static void 1404carp_setrun(struct carp_softc *sc, sa_family_t af) 1405{ 1406 struct timeval tv; 1407 | 1118 } 1119} 1120 1121/* 1122 * When in backup state, af indicates whether to reset the master down timer 1123 * for v4 or v6. If it's set to zero, reset the ones which are already pending. 1124 */ 1125static void 1126carp_setrun(struct carp_softc *sc, sa_family_t af) 1127{ 1128 struct timeval tv; 1129 |
1408 if (sc->sc_carpdev == NULL) { 1409 SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 1410 carp_set_state(sc, INIT); 1411 return; 1412 } else 1413 CARP_SCLOCK_ASSERT(sc); | 1130 CARP_LOCK_ASSERT(sc); |
1414 | 1131 |
1415 if (SC2IFP(sc)->if_flags & IFF_UP && 1416 sc->sc_vhid > 0 && (sc->sc_naddrs || sc->sc_naddrs6) && 1417 sc->sc_carpdev->if_link_state == LINK_STATE_UP) 1418 SC2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; 1419 else { 1420 SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 1421 carp_setroute(sc, RTM_DELETE); | 1132 if ((sc->sc_carpdev->if_flags & IFF_UP) == 0 || 1133 sc->sc_carpdev->if_link_state != LINK_STATE_UP || 1134 (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)) |
1422 return; | 1135 return; |
1423 } | |
1424 1425 switch (sc->sc_state) { 1426 case INIT: | 1136 1137 switch (sc->sc_state) { 1138 case INIT: |
1427 CARP_LOG("%s: INIT -> BACKUP\n", SC2IFP(sc)->if_xname); | 1139 CARP_LOG("VHID %u@%s: INIT -> BACKUP\n", 1140 sc->sc_vhid, 1141 sc->sc_carpdev->if_xname); |
1428 carp_set_state(sc, BACKUP); | 1142 carp_set_state(sc, BACKUP); |
1429 carp_setroute(sc, RTM_DELETE); | |
1430 carp_setrun(sc, 0); 1431 break; 1432 case BACKUP: 1433 callout_stop(&sc->sc_ad_tmo); 1434 tv.tv_sec = 3 * sc->sc_advbase; 1435 tv.tv_usec = sc->sc_advskew * 1000000 / 256; 1436 switch (af) { 1437#ifdef INET 1438 case AF_INET: 1439 callout_reset(&sc->sc_md_tmo, tvtohz(&tv), 1440 carp_master_down, sc); 1441 break; | 1143 carp_setrun(sc, 0); 1144 break; 1145 case BACKUP: 1146 callout_stop(&sc->sc_ad_tmo); 1147 tv.tv_sec = 3 * sc->sc_advbase; 1148 tv.tv_usec = sc->sc_advskew * 1000000 / 256; 1149 switch (af) { 1150#ifdef INET 1151 case AF_INET: 1152 callout_reset(&sc->sc_md_tmo, tvtohz(&tv), 1153 carp_master_down, sc); 1154 break; |
1442#endif /* INET */ | 1155#endif |
1443#ifdef INET6 1444 case AF_INET6: 1445 callout_reset(&sc->sc_md6_tmo, tvtohz(&tv), 1446 carp_master_down, sc); 1447 break; | 1156#ifdef INET6 1157 case AF_INET6: 1158 callout_reset(&sc->sc_md6_tmo, tvtohz(&tv), 1159 carp_master_down, sc); 1160 break; |
1448#endif /* INET6 */ | 1161#endif |
1449 default: | 1162 default: |
1163#ifdef INET |
|
1450 if (sc->sc_naddrs) 1451 callout_reset(&sc->sc_md_tmo, tvtohz(&tv), 1452 carp_master_down, sc); | 1164 if (sc->sc_naddrs) 1165 callout_reset(&sc->sc_md_tmo, tvtohz(&tv), 1166 carp_master_down, sc); |
1167#endif 1168#ifdef INET6 |
|
1453 if (sc->sc_naddrs6) 1454 callout_reset(&sc->sc_md6_tmo, tvtohz(&tv), 1455 carp_master_down, sc); | 1169 if (sc->sc_naddrs6) 1170 callout_reset(&sc->sc_md6_tmo, tvtohz(&tv), 1171 carp_master_down, sc); |
1172#endif |
|
1456 break; 1457 } 1458 break; 1459 case MASTER: 1460 tv.tv_sec = sc->sc_advbase; 1461 tv.tv_usec = sc->sc_advskew * 1000000 / 256; 1462 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 1463 carp_send_ad, sc); 1464 break; 1465 } 1466} 1467 | 1173 break; 1174 } 1175 break; 1176 case MASTER: 1177 tv.tv_sec = sc->sc_advbase; 1178 tv.tv_usec = sc->sc_advskew * 1000000 / 256; 1179 callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), 1180 carp_send_ad, sc); 1181 break; 1182 } 1183} 1184 |
1468#ifdef INET 1469static void 1470carp_multicast_cleanup(struct carp_softc *sc, int dofree) | 1185/* 1186 * Setup multicast structures. 1187 */ 1188static int 1189carp_multicast_setup(struct carp_softc *sc, sa_family_t sa) |
1471{ | 1190{ |
1472 struct ip_moptions *imo = &sc->sc_imo; 1473 u_int16_t n = imo->imo_num_memberships; | 1191 struct ifnet *ifp = sc->sc_carpdev; 1192 struct carp_if *cif = ifp->if_carp; 1193 int error = 0; |
1474 | 1194 |
1475 /* Clean up our own multicast memberships */ 1476 while (n-- > 0) { 1477 if (imo->imo_membership[n] != NULL) { 1478 if (dofree) 1479 in_delmulti(imo->imo_membership[n]); 1480 imo->imo_membership[n] = NULL; | 1195 switch (sa) { 1196#ifdef INET 1197 case AF_INET: 1198 { 1199 struct ip_moptions *imo = &cif->cif_imo; 1200 struct in_addr addr; 1201 1202 if (imo->imo_membership) 1203 return (0); 1204 1205 imo->imo_membership = (struct in_multi **)malloc( 1206 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, 1207 M_WAITOK); 1208 imo->imo_mfilters = NULL; 1209 imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 1210 imo->imo_multicast_vif = -1; 1211 1212 addr.s_addr = htonl(INADDR_CARP_GROUP); 1213 if ((error = in_joingroup(ifp, &addr, NULL, 1214 &imo->imo_membership[0])) != 0) { 1215 free(imo->imo_membership, M_CARP); 1216 break; |
1481 } | 1217 } |
1218 imo->imo_num_memberships++; 1219 imo->imo_multicast_ifp = ifp; 1220 imo->imo_multicast_ttl = CARP_DFLTTL; 1221 imo->imo_multicast_loop = 0; 1222 break; 1223 } 1224#endif 1225#ifdef INET6 1226 case AF_INET6: 1227 { 1228 struct ip6_moptions *im6o = &cif->cif_im6o; 1229 struct in6_addr in6; 1230 struct in6_multi *in6m; 1231 1232 if (im6o->im6o_membership) 1233 return (0); 1234 1235 im6o->im6o_membership = (struct in6_multi **)malloc( 1236 (sizeof(struct in6_multi *) * IPV6_MIN_MEMBERSHIPS), M_CARP, 1237 M_ZERO|M_WAITOK); 1238 im6o->im6o_mfilters = NULL; 1239 im6o->im6o_max_memberships = IPV6_MIN_MEMBERSHIPS; 1240 im6o->im6o_multicast_hlim = CARP_DFLTTL; 1241 im6o->im6o_multicast_ifp = ifp; 1242 1243 /* Join IPv6 CARP multicast group. */ 1244 bzero(&in6, sizeof(in6)); 1245 in6.s6_addr16[0] = htons(0xff02); 1246 in6.s6_addr8[15] = 0x12; 1247 if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { 1248 free(im6o->im6o_membership, M_CARP); 1249 break; 1250 } 1251 in6m = NULL; 1252 if ((error = in6_mc_join(ifp, &in6, NULL, &in6m, 0)) != 0) { 1253 free(im6o->im6o_membership, M_CARP); 1254 break; 1255 } 1256 im6o->im6o_membership[0] = in6m; 1257 im6o->im6o_num_memberships++; 1258 1259 /* Join solicited multicast address. */ 1260 bzero(&in6, sizeof(in6)); 1261 in6.s6_addr16[0] = htons(0xff02); 1262 in6.s6_addr32[1] = 0; 1263 in6.s6_addr32[2] = htonl(1); 1264 in6.s6_addr32[3] = 0; 1265 in6.s6_addr8[12] = 0xff; 1266 if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { 1267 in6_mc_leave(im6o->im6o_membership[0], NULL); 1268 free(im6o->im6o_membership, M_CARP); 1269 break; 1270 } 1271 in6m = NULL; 1272 if ((error = in6_mc_join(ifp, &in6, NULL, &in6m, 0)) != 0) { 1273 in6_mc_leave(im6o->im6o_membership[0], NULL); 1274 free(im6o->im6o_membership, M_CARP); 1275 break; 1276 } 1277 im6o->im6o_membership[1] = in6m; 1278 im6o->im6o_num_memberships++; 1279 break; 1280 } 1281#endif |
|
1482 } | 1282 } |
1483 KASSERT(imo->imo_mfilters == NULL, 1484 ("%s: imo_mfilters != NULL", __func__)); 1485 imo->imo_num_memberships = 0; 1486 imo->imo_multicast_ifp = NULL; | 1283 1284 return (error); |
1487} | 1285} |
1488#endif | |
1489 | 1286 |
1490#ifdef INET6 | 1287/* 1288 * Free multicast structures. 1289 */ |
1491static void | 1290static void |
1492carp_multicast6_cleanup(struct carp_softc *sc, int dofree) | 1291carp_multicast_cleanup(struct carp_softc *sc, sa_family_t sa) |
1493{ | 1292{ |
1494 struct ip6_moptions *im6o = &sc->sc_im6o; 1495 u_int16_t n = im6o->im6o_num_memberships; | 1293 struct ifnet *ifp = sc->sc_carpdev; 1294 struct carp_if *cif = ifp->if_carp; |
1496 | 1295 |
1497 while (n-- > 0) { 1498 if (im6o->im6o_membership[n] != NULL) { 1499 if (dofree) 1500 in6_mc_leave(im6o->im6o_membership[n], NULL); 1501 im6o->im6o_membership[n] = NULL; | 1296 switch (sa) { 1297#ifdef INET 1298 case AF_INET: 1299 if (sc->sc_naddrs == 0) { 1300 struct ip_moptions *imo = &cif->cif_imo; 1301 1302 in_leavegroup(imo->imo_membership[0], NULL); 1303 KASSERT(imo->imo_mfilters == NULL, 1304 ("%s: imo_mfilters != NULL", __func__)); 1305 free(imo->imo_membership, M_CARP); 1306 imo->imo_membership = NULL; 1307 |
1502 } | 1308 } |
1309 break; 1310#endif 1311#ifdef INET6 1312 case AF_INET6: 1313 if (sc->sc_naddrs6 == 0) { 1314 struct ip6_moptions *im6o = &cif->cif_im6o; 1315 1316 in6_mc_leave(im6o->im6o_membership[0], NULL); 1317 in6_mc_leave(im6o->im6o_membership[1], NULL); 1318 KASSERT(im6o->im6o_mfilters == NULL, 1319 ("%s: im6o_mfilters != NULL", __func__)); 1320 free(im6o->im6o_membership, M_CARP); 1321 im6o->im6o_membership = NULL; 1322 } 1323 break; 1324#endif |
|
1503 } | 1325 } |
1504 KASSERT(im6o->im6o_mfilters == NULL, 1505 ("%s: im6o_mfilters != NULL", __func__)); 1506 im6o->im6o_num_memberships = 0; 1507 im6o->im6o_multicast_ifp = NULL; | |
1508} | 1326} |
1509#endif | |
1510 | 1327 |
1511#ifdef INET 1512static int 1513carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) | 1328int 1329carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa) |
1514{ | 1330{ |
1515 struct ifnet *ifp; 1516 struct carp_if *cif; 1517 struct in_ifaddr *ia, *ia_if; 1518 struct ip_moptions *imo = &sc->sc_imo; 1519 struct in_addr addr; 1520 u_long iaddr = htonl(sin->sin_addr.s_addr); 1521 int own, error; | 1331 struct m_tag *mtag; 1332 struct carp_softc *sc; |
1522 | 1333 |
1523 if (sin->sin_addr.s_addr == 0) { 1524 if (!(SC2IFP(sc)->if_flags & IFF_UP)) 1525 carp_set_state(sc, INIT); 1526 if (sc->sc_naddrs) 1527 SC2IFP(sc)->if_flags |= IFF_UP; 1528 if (sc->sc_carpdev) 1529 CARP_SCLOCK(sc); 1530 carp_setrun(sc, 0); 1531 if (sc->sc_carpdev) 1532 CARP_SCUNLOCK(sc); | 1334 if (!sa) |
1533 return (0); | 1335 return (0); |
1534 } | |
1535 | 1336 |
1536 /* we have to do it by hands to check we won't match on us */ 1537 ia_if = NULL; own = 0; 1538 IN_IFADDR_RLOCK(); 1539 TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 1540 /* and, yeah, we need a multicast-capable iface too */ 1541 if (ia->ia_ifp != SC2IFP(sc) && 1542 (ia->ia_ifp->if_flags & IFF_MULTICAST) && 1543 (iaddr & ia->ia_subnetmask) == ia->ia_subnet) { 1544 if (!ia_if) 1545 ia_if = ia; 1546 if (sin->sin_addr.s_addr == 1547 ia->ia_addr.sin_addr.s_addr) 1548 own++; 1549 } | 1337 switch (sa->sa_family) { 1338#ifdef INET 1339 case AF_INET: 1340 break; 1341#endif 1342#ifdef INET6 1343 case AF_INET6: 1344 break; 1345#endif 1346 default: 1347 return (0); |
1550 } 1551 | 1348 } 1349 |
1552 if (!ia_if) { 1553 IN_IFADDR_RUNLOCK(); 1554 return (EADDRNOTAVAIL); 1555 } | 1350 mtag = m_tag_find(m, PACKET_TAG_CARP, NULL); 1351 if (mtag == NULL) 1352 return (0); |
1556 | 1353 |
1557 ia = ia_if; 1558 ifa_ref(&ia->ia_ifa); 1559 IN_IFADDR_RUNLOCK(); | 1354 bcopy(mtag + 1, &sc, sizeof(struct carp_softc *)); |
1560 | 1355 |
1561 ifp = ia->ia_ifp; | 1356 /* Set the source MAC address to the Virtual Router MAC Address. */ 1357 switch (ifp->if_type) { 1358 case IFT_ETHER: 1359 case IFT_L2VLAN: { 1360 struct ether_header *eh; |
1562 | 1361 |
1563 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 || 1564 (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp)) { 1565 ifa_free(&ia->ia_ifa); 1566 return (EADDRNOTAVAIL); 1567 } 1568 1569 if (imo->imo_num_memberships == 0) { 1570 addr.s_addr = htonl(INADDR_CARP_GROUP); 1571 if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == 1572 NULL) { 1573 ifa_free(&ia->ia_ifa); 1574 return (ENOBUFS); | 1362 eh = mtod(m, struct ether_header *); 1363 eh->ether_shost[0] = 0; 1364 eh->ether_shost[1] = 0; 1365 eh->ether_shost[2] = 0x5e; 1366 eh->ether_shost[3] = 0; 1367 eh->ether_shost[4] = 1; 1368 eh->ether_shost[5] = sc->sc_vhid; |
1575 } | 1369 } |
1576 imo->imo_num_memberships++; 1577 imo->imo_multicast_ifp = ifp; 1578 imo->imo_multicast_ttl = CARP_DFLTTL; 1579 imo->imo_multicast_loop = 0; 1580 } | 1370 break; 1371 case IFT_FDDI: { 1372 struct fddi_header *fh; |
1581 | 1373 |
1582 if (!ifp->if_carp) { 1583 1584 cif = malloc(sizeof(*cif), M_CARP, 1585 M_WAITOK|M_ZERO); 1586 if (!cif) { 1587 error = ENOBUFS; 1588 goto cleanup; | 1374 fh = mtod(m, struct fddi_header *); 1375 fh->fddi_shost[0] = 0; 1376 fh->fddi_shost[1] = 0; 1377 fh->fddi_shost[2] = 0x5e; 1378 fh->fddi_shost[3] = 0; 1379 fh->fddi_shost[4] = 1; 1380 fh->fddi_shost[5] = sc->sc_vhid; |
1589 } | 1381 } |
1590 if ((error = ifpromisc(ifp, 1))) { 1591 free(cif, M_CARP); 1592 goto cleanup; | 1382 break; 1383 case IFT_ISO88025: { 1384 struct iso88025_header *th; 1385 th = mtod(m, struct iso88025_header *); 1386 th->iso88025_shost[0] = 3; 1387 th->iso88025_shost[1] = 0; 1388 th->iso88025_shost[2] = 0x40 >> (sc->sc_vhid - 1); 1389 th->iso88025_shost[3] = 0x40000 >> (sc->sc_vhid - 1); 1390 th->iso88025_shost[4] = 0; 1391 th->iso88025_shost[5] = 0; |
1593 } | 1392 } |
1594 1595 CARP_LOCK_INIT(cif); 1596 CARP_LOCK(cif); 1597 cif->vhif_ifp = ifp; 1598 TAILQ_INIT(&cif->vhif_vrs); 1599 ifp->if_carp = cif; 1600 1601 } else { 1602 struct carp_softc *vr; 1603 1604 cif = (struct carp_if *)ifp->if_carp; 1605 CARP_LOCK(cif); 1606 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) 1607 if (vr != sc && vr->sc_vhid == sc->sc_vhid) { 1608 CARP_UNLOCK(cif); 1609 error = EEXIST; 1610 goto cleanup; 1611 } | 1393 break; 1394 default: 1395 printf("%s: carp is not supported for the %d interface type\n", 1396 ifp->if_xname, ifp->if_type); 1397 return (EOPNOTSUPP); |
1612 } | 1398 } |
1613 sc->sc_ia = ia; 1614 sc->sc_carpdev = ifp; | |
1615 | 1399 |
1616 { /* XXX prevent endless loop if already in queue */ 1617 struct carp_softc *vr, *after = NULL; 1618 int myself = 0; 1619 cif = (struct carp_if *)ifp->if_carp; | 1400 return (0); 1401} |
1620 | 1402 |
1621 /* XXX: cif should not change, right? So we still hold the lock */ 1622 CARP_LOCK_ASSERT(cif); | 1403static struct carp_softc* 1404carp_alloc(struct ifnet *ifp) 1405{ 1406 struct carp_softc *sc; 1407 struct carp_if *cif; |
1623 | 1408 |
1624 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { 1625 if (vr == sc) 1626 myself = 1; 1627 if (vr->sc_vhid < sc->sc_vhid) 1628 after = vr; | 1409 if ((cif = ifp->if_carp) == NULL) { 1410 cif = carp_alloc_if(ifp); 1411 if (cif == NULL) 1412 return (NULL); |
1629 } 1630 | 1413 } 1414 |
1631 if (!myself) { 1632 /* We're trying to keep things in order */ 1633 if (after == NULL) { 1634 TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list); 1635 } else { 1636 TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list); 1637 } 1638 cif->vhif_nvrs++; 1639 } 1640 } | 1415 sc = malloc(sizeof(*sc), M_CARP, M_WAITOK|M_ZERO); |
1641 | 1416 |
1642 sc->sc_naddrs++; 1643 SC2IFP(sc)->if_flags |= IFF_UP; 1644 if (own) 1645 sc->sc_advskew = 0; 1646 carp_sc_state_locked(sc); 1647 carp_setrun(sc, 0); | 1417 sc->sc_advbase = CARP_DFLTINTV; 1418 sc->sc_vhid = -1; /* required setting */ 1419 sc->sc_init_counter = 1; 1420 sc->sc_state = INIT; |
1648 | 1421 |
1649 CARP_UNLOCK(cif); 1650 ifa_free(&ia->ia_ifa); /* XXXRW: should hold reference for softc. */ | 1422 sc->sc_ifasiz = sizeof(struct ifaddr *); 1423 sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO); 1424 sc->sc_carpdev = ifp; |
1651 | 1425 |
1652 return (0); | 1426 CARP_LOCK_INIT(sc); 1427#ifdef INET 1428 callout_init_mtx(&sc->sc_md_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED); 1429#endif 1430#ifdef INET6 1431 callout_init_mtx(&sc->sc_md6_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED); 1432#endif 1433 callout_init_mtx(&sc->sc_ad_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED); |
1653 | 1434 |
1654cleanup: 1655 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1656 ifa_free(&ia->ia_ifa); 1657 return (error); | 1435 CIF_LOCK(cif); 1436 TAILQ_INSERT_TAIL(&cif->cif_vrs, sc, sc_list); 1437 CIF_UNLOCK(cif); 1438 1439 mtx_lock(&carp_mtx); 1440 LIST_INSERT_HEAD(&carp_list, sc, sc_next); 1441 mtx_unlock(&carp_mtx); 1442 1443 return (sc); |
1658} 1659 1660static int | 1444} 1445 1446static int |
1661carp_del_addr(struct carp_softc *sc, struct sockaddr_in *sin) | 1447carp_grow_ifas(struct carp_softc *sc) |
1662{ | 1448{ |
1663 int error = 0; | 1449 struct ifaddr **new; |
1664 | 1450 |
1665 if (!--sc->sc_naddrs) { 1666 struct carp_if *cif = (struct carp_if *)sc->sc_carpdev->if_carp; 1667 struct ip_moptions *imo = &sc->sc_imo; | 1451 CARP_LOCK_ASSERT(sc); |
1668 | 1452 |
1669 CARP_LOCK(cif); 1670 callout_stop(&sc->sc_ad_tmo); 1671 SC2IFP(sc)->if_flags &= ~IFF_UP; 1672 SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 1673 sc->sc_vhid = -1; 1674 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1675 imo->imo_multicast_ifp = NULL; 1676 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list); 1677 if (!--cif->vhif_nvrs) { 1678 sc->sc_carpdev->if_carp = NULL; 1679 CARP_LOCK_DESTROY(cif); 1680 free(cif, M_CARP); 1681 } else { 1682 CARP_UNLOCK(cif); 1683 } 1684 } | 1453 new = malloc(sc->sc_ifasiz * 2, M_CARP, M_NOWAIT|M_ZERO); 1454 if (new == NULL) 1455 return (ENOMEM); 1456 bcopy(sc->sc_ifas, new, sc->sc_ifasiz); 1457 free(sc->sc_ifas, M_CARP); 1458 sc->sc_ifas = new; 1459 sc->sc_ifasiz *= 2; |
1685 | 1460 |
1686 return (error); | 1461 return (0); |
1687} | 1462} |
1688#endif | |
1689 | 1463 |
1690#ifdef INET6 1691static int 1692carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) | 1464static void 1465carp_destroy(struct carp_softc *sc) |
1693{ | 1466{ |
1694 struct ifnet *ifp; 1695 struct carp_if *cif; 1696 struct in6_ifaddr *ia, *ia_if; 1697 struct ip6_moptions *im6o = &sc->sc_im6o; 1698 struct in6_addr in6; 1699 int own, error; | 1467 struct ifnet *ifp = sc->sc_carpdev; 1468 struct carp_if *cif = ifp->if_carp; |
1700 | 1469 |
1701 error = 0; | 1470 CIF_LOCK(cif); 1471 TAILQ_REMOVE(&cif->cif_vrs, sc, sc_list); 1472 if (TAILQ_EMPTY(&cif->cif_vrs)) 1473 carp_free_if(cif); 1474 else 1475 CIF_UNLOCK(cif); |
1702 | 1476 |
1703 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1704 if (!(SC2IFP(sc)->if_flags & IFF_UP)) 1705 carp_set_state(sc, INIT); 1706 if (sc->sc_naddrs6) 1707 SC2IFP(sc)->if_flags |= IFF_UP; 1708 if (sc->sc_carpdev) 1709 CARP_SCLOCK(sc); 1710 carp_setrun(sc, 0); 1711 if (sc->sc_carpdev) 1712 CARP_SCUNLOCK(sc); 1713 return (0); 1714 } | 1477 mtx_lock(&carp_mtx); 1478 LIST_REMOVE(sc, sc_next); 1479 mtx_unlock(&carp_mtx); |
1715 | 1480 |
1716 /* we have to do it by hands to check we won't match on us */ 1717 ia_if = NULL; own = 0; 1718 IN6_IFADDR_RLOCK(); 1719 TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 1720 int i; | 1481 CARP_LOCK(sc); 1482 callout_drain(&sc->sc_ad_tmo); 1483#ifdef INET 1484 callout_drain(&sc->sc_md_tmo); 1485#endif 1486#ifdef INET6 1487 callout_drain(&sc->sc_md6_tmo); 1488#endif 1489 CARP_LOCK_DESTROY(sc); |
1721 | 1490 |
1722 for (i = 0; i < 4; i++) { 1723 if ((sin6->sin6_addr.s6_addr32[i] & 1724 ia->ia_prefixmask.sin6_addr.s6_addr32[i]) != 1725 (ia->ia_addr.sin6_addr.s6_addr32[i] & 1726 ia->ia_prefixmask.sin6_addr.s6_addr32[i])) 1727 break; 1728 } 1729 /* and, yeah, we need a multicast-capable iface too */ 1730 if (ia->ia_ifp != SC2IFP(sc) && 1731 (ia->ia_ifp->if_flags & IFF_MULTICAST) && 1732 (i == 4)) { 1733 if (!ia_if) 1734 ia_if = ia; 1735 if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 1736 &ia->ia_addr.sin6_addr)) 1737 own++; 1738 } 1739 } | 1491 free(sc->sc_ifas, M_CARP); 1492 free(sc, M_CARP); 1493} |
1740 | 1494 |
1741 if (!ia_if) { 1742 IN6_IFADDR_RUNLOCK(); 1743 return (EADDRNOTAVAIL); 1744 } 1745 ia = ia_if; 1746 ifa_ref(&ia->ia_ifa); 1747 IN6_IFADDR_RUNLOCK(); 1748 ifp = ia->ia_ifp; | 1495static struct carp_if* 1496carp_alloc_if(struct ifnet *ifp) 1497{ 1498 struct carp_if *cif; |
1749 | 1499 |
1750 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 || 1751 (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp != ifp)) { 1752 ifa_free(&ia->ia_ifa); 1753 return (EADDRNOTAVAIL); 1754 } | 1500 cif = malloc(sizeof(*cif), M_CARP, M_WAITOK|M_ZERO); |
1755 | 1501 |
1756 if (!sc->sc_naddrs6) { 1757 struct in6_multi *in6m; | 1502 if (ifpromisc(ifp, 1) != 0) 1503 goto cleanup; |
1758 | 1504 |
1759 im6o->im6o_multicast_ifp = ifp; | 1505 CIF_LOCK_INIT(cif); 1506 cif->cif_ifp = ifp; 1507 TAILQ_INIT(&cif->cif_vrs); |
1760 | 1508 |
1761 /* join CARP multicast address */ 1762 bzero(&in6, sizeof(in6)); 1763 in6.s6_addr16[0] = htons(0xff02); 1764 in6.s6_addr8[15] = 0x12; 1765 if (in6_setscope(&in6, ifp, NULL) != 0) 1766 goto cleanup; 1767 in6m = NULL; 1768 error = in6_mc_join(ifp, &in6, NULL, &in6m, 0); 1769 if (error) 1770 goto cleanup; 1771 im6o->im6o_membership[0] = in6m; 1772 im6o->im6o_num_memberships++; | 1509 IF_ADDR_LOCK(ifp); 1510 ifp->if_carp = cif; 1511 if_ref(ifp); 1512 IF_ADDR_UNLOCK(ifp); |
1773 | 1513 |
1774 /* join solicited multicast address */ 1775 bzero(&in6, sizeof(in6)); 1776 in6.s6_addr16[0] = htons(0xff02); 1777 in6.s6_addr32[1] = 0; 1778 in6.s6_addr32[2] = htonl(1); 1779 in6.s6_addr32[3] = sin6->sin6_addr.s6_addr32[3]; 1780 in6.s6_addr8[12] = 0xff; 1781 if (in6_setscope(&in6, ifp, NULL) != 0) 1782 goto cleanup; 1783 in6m = NULL; 1784 error = in6_mc_join(ifp, &in6, NULL, &in6m, 0); 1785 if (error) 1786 goto cleanup; 1787 im6o->im6o_membership[1] = in6m; 1788 im6o->im6o_num_memberships++; 1789 } | 1514 return (cif); |
1790 | 1515 |
1791 if (!ifp->if_carp) { 1792 cif = malloc(sizeof(*cif), M_CARP, 1793 M_WAITOK|M_ZERO); 1794 if (!cif) { 1795 error = ENOBUFS; 1796 goto cleanup; 1797 } 1798 if ((error = ifpromisc(ifp, 1))) { 1799 free(cif, M_CARP); 1800 goto cleanup; 1801 } | 1516cleanup: 1517 free(cif, M_CARP); |
1802 | 1518 |
1803 CARP_LOCK_INIT(cif); 1804 CARP_LOCK(cif); 1805 cif->vhif_ifp = ifp; 1806 TAILQ_INIT(&cif->vhif_vrs); 1807 ifp->if_carp = cif; | 1519 return (NULL); 1520} |
1808 | 1521 |
1809 } else { 1810 struct carp_softc *vr; | 1522static void 1523carp_free_if(struct carp_if *cif) 1524{ 1525 struct ifnet *ifp = cif->cif_ifp; |
1811 | 1526 |
1812 cif = (struct carp_if *)ifp->if_carp; 1813 CARP_LOCK(cif); 1814 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) 1815 if (vr != sc && vr->sc_vhid == sc->sc_vhid) { 1816 CARP_UNLOCK(cif); 1817 error = EINVAL; 1818 goto cleanup; 1819 } 1820 } 1821 sc->sc_ia6 = ia; 1822 sc->sc_carpdev = ifp; | 1527 CIF_LOCK_ASSERT(cif); 1528 KASSERT(TAILQ_EMPTY(&cif->cif_vrs), ("%s: softc list not empty", 1529 __func__)); |
1823 | 1530 |
1824 { /* XXX prevent endless loop if already in queue */ 1825 struct carp_softc *vr, *after = NULL; 1826 int myself = 0; 1827 cif = (struct carp_if *)ifp->if_carp; 1828 CARP_LOCK_ASSERT(cif); | 1531 IF_ADDR_LOCK(ifp); 1532 ifp->if_carp = NULL; 1533 if_rele(ifp); 1534 IF_ADDR_UNLOCK(ifp); |
1829 | 1535 |
1830 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { 1831 if (vr == sc) 1832 myself = 1; 1833 if (vr->sc_vhid < sc->sc_vhid) 1834 after = vr; 1835 } | 1536 CIF_LOCK_DESTROY(cif); |
1836 | 1537 |
1837 if (!myself) { 1838 /* We're trying to keep things in order */ 1839 if (after == NULL) { 1840 TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list); 1841 } else { 1842 TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list); 1843 } 1844 cif->vhif_nvrs++; 1845 } 1846 } | 1538 ifpromisc(ifp, 0); |
1847 | 1539 |
1848 sc->sc_naddrs6++; 1849 SC2IFP(sc)->if_flags |= IFF_UP; 1850 if (own) 1851 sc->sc_advskew = 0; 1852 carp_sc_state_locked(sc); 1853 carp_setrun(sc, 0); 1854 1855 CARP_UNLOCK(cif); 1856 ifa_free(&ia->ia_ifa); /* XXXRW: should hold reference for softc. */ 1857 1858 return (0); 1859 1860cleanup: 1861 if (!sc->sc_naddrs6) 1862 carp_multicast6_cleanup(sc, 1); 1863 ifa_free(&ia->ia_ifa); 1864 return (error); | 1540 free(cif, M_CARP); |
1865} 1866 | 1541} 1542 |
1867static int 1868carp_del_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) | 1543static void 1544carp_carprcp(struct carpreq *carpr, struct carp_softc *sc, int priv) |
1869{ | 1545{ |
1870 int error = 0; | |
1871 | 1546 |
1872 if (!--sc->sc_naddrs6) { 1873 struct carp_if *cif = (struct carp_if *)sc->sc_carpdev->if_carp; 1874 1875 CARP_LOCK(cif); 1876 callout_stop(&sc->sc_ad_tmo); 1877 SC2IFP(sc)->if_flags &= ~IFF_UP; 1878 SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 1879 sc->sc_vhid = -1; 1880 carp_multicast6_cleanup(sc, 1); 1881 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list); 1882 if (!--cif->vhif_nvrs) { 1883 CARP_LOCK_DESTROY(cif); 1884 sc->sc_carpdev->if_carp = NULL; 1885 free(cif, M_CARP); 1886 } else 1887 CARP_UNLOCK(cif); 1888 } 1889 1890 return (error); | 1547 CARP_LOCK(sc); 1548 carpr->carpr_state = sc->sc_state; 1549 carpr->carpr_vhid = sc->sc_vhid; 1550 carpr->carpr_advbase = sc->sc_advbase; 1551 carpr->carpr_advskew = sc->sc_advskew; 1552 if (priv) 1553 bcopy(sc->sc_key, carpr->carpr_key, sizeof(carpr->carpr_key)); 1554 else 1555 bzero(carpr->carpr_key, sizeof(carpr->carpr_key)); 1556 CARP_UNLOCK(sc); |
1891} | 1557} |
1892#endif /* INET6 */ | |
1893 | 1558 |
1894static int 1895carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) | 1559int 1560carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td) |
1896{ | 1561{ |
1897 struct carp_softc *sc = ifp->if_softc, *vr; | |
1898 struct carpreq carpr; | 1562 struct carpreq carpr; |
1899 struct ifaddr *ifa; 1900 struct ifreq *ifr; 1901 struct ifaliasreq *ifra; 1902 int locked = 0, error = 0; | 1563 struct ifnet *ifp; 1564 struct carp_softc *sc = NULL; 1565 int error = 0, locked = 0; |
1903 | 1566 |
1904 ifa = (struct ifaddr *)addr; 1905 ifra = (struct ifaliasreq *)addr; 1906 ifr = (struct ifreq *)addr; | 1567 if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr))) 1568 return (error); |
1907 | 1569 |
1908 switch (cmd) { 1909 case SIOCSIFADDR: 1910 switch (ifa->ifa_addr->sa_family) { 1911#ifdef INET 1912 case AF_INET: 1913 SC2IFP(sc)->if_flags |= IFF_UP; 1914 bcopy(ifa->ifa_addr, ifa->ifa_dstaddr, 1915 sizeof(struct sockaddr)); 1916 error = carp_set_addr(sc, satosin(ifa->ifa_addr)); 1917 break; 1918#endif /* INET */ 1919#ifdef INET6 1920 case AF_INET6: 1921 SC2IFP(sc)->if_flags |= IFF_UP; 1922 error = carp_set_addr6(sc, satosin6(ifa->ifa_addr)); 1923 break; 1924#endif /* INET6 */ 1925 default: 1926 error = EAFNOSUPPORT; 1927 break; 1928 } | 1570 ifp = ifunit_ref(ifr->ifr_name); 1571 if (ifp == NULL) 1572 return (ENXIO); 1573 1574 switch (ifp->if_type) { 1575 case IFT_ETHER: 1576 case IFT_L2VLAN: 1577 case IFT_FDDI: 1578 case IFT_ISO88025: |
1929 break; | 1579 break; |
1580 default: 1581 error = EOPNOTSUPP; 1582 goto out; 1583 } |
|
1930 | 1584 |
1931 case SIOCAIFADDR: 1932 switch (ifa->ifa_addr->sa_family) { 1933#ifdef INET 1934 case AF_INET: 1935 SC2IFP(sc)->if_flags |= IFF_UP; 1936 bcopy(ifa->ifa_addr, ifa->ifa_dstaddr, 1937 sizeof(struct sockaddr)); 1938 error = carp_set_addr(sc, satosin(&ifra->ifra_addr)); | 1585 if ((ifp->if_flags & IFF_MULTICAST) == 0) { 1586 error = EADDRNOTAVAIL; 1587 goto out; 1588 } 1589 1590 switch (cmd) { 1591 case SIOCSVH: 1592 if ((error = priv_check(td, PRIV_NETINET_CARP))) |
1939 break; | 1593 break; |
1940#endif /* INET */ 1941#ifdef INET6 1942 case AF_INET6: 1943 SC2IFP(sc)->if_flags |= IFF_UP; 1944 error = carp_set_addr6(sc, satosin6(&ifra->ifra_addr)); | 1594 if (carpr.carpr_vhid <= 0 || carpr.carpr_vhid > CARP_MAXVHID || 1595 carpr.carpr_advbase < 0 || carpr.carpr_advskew < 0) { 1596 error = EINVAL; |
1945 break; | 1597 break; |
1946#endif /* INET6 */ 1947 default: 1948 error = EAFNOSUPPORT; 1949 break; | |
1950 } | 1598 } |
1951 break; | |
1952 | 1599 |
1953 case SIOCDIFADDR: 1954 switch (ifa->ifa_addr->sa_family) { 1955#ifdef INET 1956 case AF_INET: 1957 error = carp_del_addr(sc, satosin(&ifra->ifra_addr)); 1958 break; 1959#endif /* INET */ 1960#ifdef INET6 1961 case AF_INET6: 1962 error = carp_del_addr6(sc, satosin6(&ifra->ifra_addr)); 1963 break; 1964#endif /* INET6 */ 1965 default: 1966 error = EAFNOSUPPORT; 1967 break; | 1600 if (ifp->if_carp) { 1601 CIF_LOCK(ifp->if_carp); 1602 IFNET_FOREACH_CARP(ifp, sc) 1603 if (sc->sc_vhid == carpr.carpr_vhid) 1604 break; 1605 CIF_UNLOCK(ifp->if_carp); |
1968 } | 1606 } |
1969 break; | 1607 if (sc == NULL) { 1608 sc = carp_alloc(ifp); 1609 if (sc == NULL) { 1610 error = EINVAL; /* XXX: ifpromisc failed */ 1611 break; 1612 } |
1970 | 1613 |
1971 case SIOCSIFFLAGS: 1972 if (sc->sc_carpdev) { 1973 locked = 1; 1974 CARP_SCLOCK(sc); | 1614 CARP_LOCK(sc); 1615 sc->sc_vhid = carpr.carpr_vhid; 1616 LLADDR(&sc->sc_addr)[0] = 0; 1617 LLADDR(&sc->sc_addr)[1] = 0; 1618 LLADDR(&sc->sc_addr)[2] = 0x5e; 1619 LLADDR(&sc->sc_addr)[3] = 0; 1620 LLADDR(&sc->sc_addr)[4] = 1; 1621 LLADDR(&sc->sc_addr)[5] = sc->sc_vhid; 1622 } else 1623 CARP_LOCK(sc); 1624 locked = 1; 1625 if (carpr.carpr_advbase > 0) { 1626 if (carpr.carpr_advbase > 255 || 1627 carpr.carpr_advbase < CARP_DFLTINTV) { 1628 error = EINVAL; 1629 break; 1630 } 1631 sc->sc_advbase = carpr.carpr_advbase; |
1975 } | 1632 } |
1976 if (sc->sc_state != INIT && !(ifr->ifr_flags & IFF_UP)) { 1977 callout_stop(&sc->sc_ad_tmo); 1978 callout_stop(&sc->sc_md_tmo); 1979 callout_stop(&sc->sc_md6_tmo); 1980 if (sc->sc_state == MASTER) 1981 carp_send_ad_locked(sc); 1982 carp_set_state(sc, INIT); 1983 carp_setrun(sc, 0); 1984 } else if (sc->sc_state == INIT && (ifr->ifr_flags & IFF_UP)) { 1985 SC2IFP(sc)->if_flags |= IFF_UP; 1986 carp_setrun(sc, 0); | 1633 if (carpr.carpr_advskew > 0) { 1634 if (carpr.carpr_advskew >= 255) { 1635 error = EINVAL; 1636 break; 1637 } 1638 sc->sc_advskew = carpr.carpr_advskew; |
1987 } | 1639 } |
1988 break; 1989 1990 case SIOCSVH: 1991 error = priv_check(curthread, PRIV_NETINET_CARP); 1992 if (error) 1993 break; 1994 if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr))) 1995 break; 1996 error = 1; 1997 if (sc->sc_carpdev) { 1998 locked = 1; 1999 CARP_SCLOCK(sc); | 1640 if (carpr.carpr_key[0] != '\0') { 1641 bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key)); 1642 carp_hmac_prepare(sc); |
2000 } | 1643 } |
2001 if (sc->sc_state != INIT && carpr.carpr_state != sc->sc_state) { | 1644 if (sc->sc_state != INIT && 1645 carpr.carpr_state != sc->sc_state) { |
2002 switch (carpr.carpr_state) { 2003 case BACKUP: 2004 callout_stop(&sc->sc_ad_tmo); 2005 carp_set_state(sc, BACKUP); 2006 carp_setrun(sc, 0); | 1646 switch (carpr.carpr_state) { 1647 case BACKUP: 1648 callout_stop(&sc->sc_ad_tmo); 1649 carp_set_state(sc, BACKUP); 1650 carp_setrun(sc, 0); |
2007 carp_setroute(sc, RTM_DELETE); | 1651 carp_delroute(sc); |
2008 break; 2009 case MASTER: 2010 carp_master_down_locked(sc); 2011 break; 2012 default: 2013 break; 2014 } 2015 } | 1652 break; 1653 case MASTER: 1654 carp_master_down_locked(sc); 1655 break; 1656 default: 1657 break; 1658 } 1659 } |
2016 if (carpr.carpr_vhid > 0) { 2017 if (carpr.carpr_vhid > 255) { 2018 error = EINVAL; 2019 break; 2020 } 2021 if (sc->sc_carpdev) { 2022 struct carp_if *cif; 2023 cif = (struct carp_if *)sc->sc_carpdev->if_carp; 2024 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) 2025 if (vr != sc && 2026 vr->sc_vhid == carpr.carpr_vhid) { 2027 error = EEXIST; 2028 break; 2029 } 2030 if (error == EEXIST) 2031 break; 2032 } 2033 sc->sc_vhid = carpr.carpr_vhid; 2034 IF_LLADDR(sc->sc_ifp)[0] = 0; 2035 IF_LLADDR(sc->sc_ifp)[1] = 0; 2036 IF_LLADDR(sc->sc_ifp)[2] = 0x5e; 2037 IF_LLADDR(sc->sc_ifp)[3] = 0; 2038 IF_LLADDR(sc->sc_ifp)[4] = 1; 2039 IF_LLADDR(sc->sc_ifp)[5] = sc->sc_vhid; 2040 error--; | 1660 break; 1661 1662 case SIOCGVH: 1663 { 1664 int priveleged; 1665 1666 if (carpr.carpr_vhid < 0 || carpr.carpr_vhid > CARP_MAXVHID) { 1667 error = EINVAL; 1668 break; |
2041 } | 1669 } |
2042 if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) { 2043 if (carpr.carpr_advskew >= 255) { 2044 error = EINVAL; | 1670 if (carpr.carpr_count < 1) { 1671 error = EMSGSIZE; 1672 break; 1673 } 1674 if (ifp->if_carp == NULL) { 1675 error = ENOENT; 1676 break; 1677 } 1678 1679 priveleged = (priv_check(td, PRIV_NETINET_CARP) == 0); 1680 if (carpr.carpr_vhid != 0) { 1681 CIF_LOCK(ifp->if_carp); 1682 IFNET_FOREACH_CARP(ifp, sc) 1683 if (sc->sc_vhid == carpr.carpr_vhid) 1684 break; 1685 CIF_UNLOCK(ifp->if_carp); 1686 if (sc == NULL) { 1687 error = ENOENT; |
2045 break; 2046 } | 1688 break; 1689 } |
2047 if (carpr.carpr_advbase > 255) { 2048 error = EINVAL; | 1690 carp_carprcp(&carpr, sc, priveleged); 1691 error = copyout(&carpr, ifr->ifr_data, sizeof(carpr)); 1692 } else { 1693 int i, count; 1694 1695 count = 0; 1696 CIF_LOCK(ifp->if_carp); 1697 IFNET_FOREACH_CARP(ifp, sc) 1698 count++; 1699 1700 if (count > carpr.carpr_count) { 1701 CIF_UNLOCK(ifp->if_carp); 1702 error = EMSGSIZE; |
2049 break; 2050 } | 1703 break; 1704 } |
2051 sc->sc_advbase = carpr.carpr_advbase; 2052 sc->sc_advskew = carpr.carpr_advskew; 2053 error--; | 1705 1706 i = 0; 1707 IFNET_FOREACH_CARP(ifp, sc) { 1708 carp_carprcp(&carpr, sc, priveleged); 1709 carpr.carpr_count = count; 1710 error = copyout(&carpr, ifr->ifr_data + 1711 (i * sizeof(carpr)), sizeof(carpr)); 1712 if (error) { 1713 CIF_UNLOCK(ifp->if_carp); 1714 break; 1715 } 1716 i++; 1717 } 1718 CIF_UNLOCK(ifp->if_carp); |
2054 } | 1719 } |
2055 bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key)); 2056 if (error > 0) 2057 error = EINVAL; 2058 else { 2059 error = 0; 2060 carp_setrun(sc, 0); 2061 } | |
2062 break; | 1720 break; |
2063 2064 case SIOCGVH: 2065 /* XXX: lockless read */ 2066 bzero(&carpr, sizeof(carpr)); 2067 carpr.carpr_state = sc->sc_state; 2068 carpr.carpr_vhid = sc->sc_vhid; 2069 carpr.carpr_advbase = sc->sc_advbase; 2070 carpr.carpr_advskew = sc->sc_advskew; 2071 error = priv_check(curthread, PRIV_NETINET_CARP); 2072 if (error == 0) 2073 bcopy(sc->sc_key, carpr.carpr_key, 2074 sizeof(carpr.carpr_key)); 2075 error = copyout(&carpr, ifr->ifr_data, sizeof(carpr)); 2076 break; 2077 | 1721 } |
2078 default: 2079 error = EINVAL; 2080 } 2081 | 1722 default: 1723 error = EINVAL; 1724 } 1725 |
1726out: |
|
2082 if (locked) | 1727 if (locked) |
2083 CARP_SCUNLOCK(sc); | 1728 CARP_UNLOCK(sc); 1729 if_rele(ifp); |
2084 | 1730 |
2085 carp_hmac_prepare(sc); 2086 | |
2087 return (error); 2088} 2089 | 1731 return (error); 1732} 1733 |
2090/* 2091 * XXX: this is looutput. We should eventually use it from there. 2092 */ | |
2093static int | 1734static int |
2094carp_looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 2095 struct route *ro) | 1735carp_get_vhid(struct ifaddr *ifa) |
2096{ | 1736{ |
2097 u_int32_t af; 2098 struct rtentry *rt = NULL; | |
2099 | 1737 |
2100 M_ASSERTPKTHDR(m); /* check if we have the packet header */ | 1738 if (ifa == NULL || ifa->ifa_carp == NULL) 1739 return (0); |
2101 | 1740 |
2102 if (ro != NULL) 2103 rt = ro->ro_rt; 2104 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 2105 m_freem(m); 2106 return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 2107 rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 2108 } 2109 2110 ifp->if_opackets++; 2111 ifp->if_obytes += m->m_pkthdr.len; 2112 2113 /* BPF writes need to be handled specially. */ 2114 if (dst->sa_family == AF_UNSPEC) { 2115 bcopy(dst->sa_data, &af, sizeof(af)); 2116 dst->sa_family = af; 2117 } 2118 2119#if 1 /* XXX */ 2120 switch (dst->sa_family) { 2121 case AF_INET: 2122 case AF_INET6: 2123 case AF_IPX: 2124 case AF_APPLETALK: 2125 break; 2126 default: 2127 printf("carp_looutput: af=%d unexpected\n", dst->sa_family); 2128 m_freem(m); 2129 return (EAFNOSUPPORT); 2130 } 2131#endif 2132 return(if_simloop(ifp, m, dst->sa_family, 0)); | 1741 return (ifa->ifa_carp->sc_vhid); |
2133} 2134 | 1742} 1743 |
2135/* 2136 * Start output on carp interface. This function should never be called. 2137 */ 2138static void 2139carp_start(struct ifnet *ifp) 2140{ 2141#ifdef DEBUG 2142 printf("%s: start called\n", ifp->if_xname); 2143#endif 2144} 2145 | |
2146int | 1744int |
2147carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, 2148 struct rtentry *rt) | 1745carp_attach(struct ifaddr *ifa, int vhid) |
2149{ | 1746{ |
2150 struct m_tag *mtag; | 1747 struct ifnet *ifp = ifa->ifa_ifp; |
2151 struct carp_softc *sc; | 1748 struct carp_softc *sc; |
2152 struct ifnet *carp_ifp; | 1749 int index, error; |
2153 | 1750 |
2154 if (!sa) 2155 return (0); | 1751 if (ifp->if_carp == NULL) 1752 return (ENOPROTOOPT); |
2156 | 1753 |
2157 switch (sa->sa_family) { | 1754 switch (ifa->ifa_addr->sa_family) { |
2158#ifdef INET 2159 case AF_INET: | 1755#ifdef INET 1756 case AF_INET: |
2160 break; 2161#endif /* INET */ | 1757#endif |
2162#ifdef INET6 2163 case AF_INET6: | 1758#ifdef INET6 1759 case AF_INET6: |
1760#endif |
|
2164 break; | 1761 break; |
2165#endif /* INET6 */ | |
2166 default: | 1762 default: |
2167 return (0); | 1763 return (EPROTOTYPE); |
2168 } 2169 | 1764 } 1765 |
2170 mtag = m_tag_find(m, PACKET_TAG_CARP, NULL); 2171 if (mtag == NULL) 2172 return (0); | 1766 CIF_LOCK(ifp->if_carp); 1767 IFNET_FOREACH_CARP(ifp, sc) 1768 if (sc->sc_vhid == vhid) 1769 break; 1770 CIF_UNLOCK(ifp->if_carp); 1771 if (sc == NULL) 1772 return (ENOENT); |
2173 | 1773 |
2174 bcopy(mtag + 1, &carp_ifp, sizeof(struct ifnet *)); 2175 sc = carp_ifp->if_softc; | 1774 if (ifa->ifa_carp) { 1775 if (ifa->ifa_carp->sc_vhid != vhid) 1776 carp_detach(ifa); 1777 else 1778 return (0); 1779 } |
2176 | 1780 |
2177 /* Set the source MAC address to Virtual Router MAC Address */ 2178 switch (ifp->if_type) { 2179 case IFT_ETHER: 2180 case IFT_L2VLAN: { 2181 struct ether_header *eh; | 1781 error = carp_multicast_setup(sc, ifa->ifa_addr->sa_family); 1782 if (error) 1783 return (error); |
2182 | 1784 |
2183 eh = mtod(m, struct ether_header *); 2184 eh->ether_shost[0] = 0; 2185 eh->ether_shost[1] = 0; 2186 eh->ether_shost[2] = 0x5e; 2187 eh->ether_shost[3] = 0; 2188 eh->ether_shost[4] = 1; 2189 eh->ether_shost[5] = sc->sc_vhid; | 1785 CARP_LOCK(sc); 1786 index = sc->sc_naddrs + sc->sc_naddrs6 + 1; 1787 if (index > sc->sc_ifasiz / sizeof(struct ifaddr *)) 1788 if ((error = carp_grow_ifas(sc)) != 0) { 1789 carp_multicast_cleanup(sc, 1790 ifa->ifa_addr->sa_family); 1791 CARP_UNLOCK(sc); 1792 return (error); |
2190 } | 1793 } |
2191 break; 2192 case IFT_FDDI: { 2193 struct fddi_header *fh; | |
2194 | 1794 |
2195 fh = mtod(m, struct fddi_header *); 2196 fh->fddi_shost[0] = 0; 2197 fh->fddi_shost[1] = 0; 2198 fh->fddi_shost[2] = 0x5e; 2199 fh->fddi_shost[3] = 0; 2200 fh->fddi_shost[4] = 1; 2201 fh->fddi_shost[5] = sc->sc_vhid; 2202 } | 1795 switch (ifa->ifa_addr->sa_family) { 1796#ifdef INET 1797 case AF_INET: 1798 sc->sc_naddrs++; |
2203 break; | 1799 break; |
2204 case IFT_ISO88025: { 2205 struct iso88025_header *th; 2206 th = mtod(m, struct iso88025_header *); 2207 th->iso88025_shost[0] = 3; 2208 th->iso88025_shost[1] = 0; 2209 th->iso88025_shost[2] = 0x40 >> (sc->sc_vhid - 1); 2210 th->iso88025_shost[3] = 0x40000 >> (sc->sc_vhid - 1); 2211 th->iso88025_shost[4] = 0; 2212 th->iso88025_shost[5] = 0; 2213 } | 1800#endif 1801#ifdef INET6 1802 case AF_INET6: 1803 sc->sc_naddrs6++; |
2214 break; | 1804 break; |
2215 default: 2216 printf("%s: carp is not supported for this interface type\n", 2217 ifp->if_xname); 2218 return (EOPNOTSUPP); | 1805#endif |
2219 } 2220 | 1806 } 1807 |
1808 ifa_ref(ifa); 1809 sc->sc_ifas[index - 1] = ifa; 1810 ifa->ifa_carp = sc; 1811 1812 carp_hmac_prepare(sc); 1813 carp_sc_state(sc); 1814 1815 CARP_UNLOCK(sc); 1816 |
|
2221 return (0); 2222} 2223 | 1817 return (0); 1818} 1819 |
2224static void 2225carp_set_state(struct carp_softc *sc, int state) | 1820void 1821carp_detach(struct ifaddr *ifa) |
2226{ | 1822{ |
2227 int link_state; | 1823 struct carp_softc *sc = ifa->ifa_carp; 1824 int i, index; |
2228 | 1825 |
2229 if (sc->sc_carpdev) 2230 CARP_SCLOCK_ASSERT(sc); | 1826 KASSERT(sc != NULL, ("%s: %p not attached", __func__, ifa)); |
2231 | 1827 |
2232 if (sc->sc_state == state) 2233 return; | 1828 CARP_LOCK(sc); |
2234 | 1829 |
2235 sc->sc_state = state; 2236 switch (state) { 2237 case BACKUP: 2238 link_state = LINK_STATE_DOWN; | 1830 /* Shift array. */ 1831 index = sc->sc_naddrs + sc->sc_naddrs6; 1832 for (i = 0; i < index; i++) 1833 if (sc->sc_ifas[i] == ifa) 1834 break; 1835 KASSERT(i < index, ("%s: %p no backref", __func__, ifa)); 1836 for (; i < index - 1; i++) 1837 sc->sc_ifas[i] = sc->sc_ifas[i+1]; 1838 sc->sc_ifas[index - 1] = NULL; 1839 1840 switch (ifa->ifa_addr->sa_family) { 1841#ifdef INET 1842 case AF_INET: 1843 sc->sc_naddrs--; |
2239 break; | 1844 break; |
2240 case MASTER: 2241 link_state = LINK_STATE_UP; | 1845#endif 1846#ifdef INET6 1847 case AF_INET6: 1848 sc->sc_naddrs6--; |
2242 break; | 1849 break; |
2243 default: 2244 link_state = LINK_STATE_UNKNOWN; 2245 break; | 1850#endif |
2246 } | 1851 } |
2247 if_link_state_change(SC2IFP(sc), link_state); | 1852 1853 carp_multicast_cleanup(sc, ifa->ifa_addr->sa_family); 1854 1855 ifa->ifa_carp = NULL; 1856 ifa_free(ifa); 1857 1858 carp_hmac_prepare(sc); 1859 carp_sc_state(sc); 1860 1861 if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) { 1862 CARP_UNLOCK(sc); 1863 carp_destroy(sc); 1864 } else 1865 CARP_UNLOCK(sc); |
2248} 2249 | 1866} 1867 |
2250void 2251carp_carpdev_state(struct ifnet *ifp) | 1868static void 1869carp_set_state(struct carp_softc *sc, int state) |
2252{ | 1870{ |
2253 struct carp_if *cif; | |
2254 | 1871 |
2255 cif = ifp->if_carp; 2256 CARP_LOCK(cif); 2257 carp_carpdev_state_locked(cif); 2258 CARP_UNLOCK(cif); | 1872 CARP_LOCK_ASSERT(sc); 1873 1874 if (sc->sc_state != state) { 1875 const char *carp_states[] = { CARP_STATES }; 1876 char subsys[IFNAMSIZ+5]; 1877 1878 sc->sc_state = state; 1879 1880 snprintf(subsys, IFNAMSIZ+5, "%u@%s", sc->sc_vhid, 1881 sc->sc_carpdev->if_xname); 1882 devctl_notify("CARP", subsys, carp_states[state], NULL); 1883 } |
2259} 2260 2261static void | 1884} 1885 1886static void |
2262carp_carpdev_state_locked(struct carp_if *cif) | 1887carp_linkstate(struct ifnet *ifp) |
2263{ 2264 struct carp_softc *sc; 2265 | 1888{ 1889 struct carp_softc *sc; 1890 |
2266 TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) 2267 carp_sc_state_locked(sc); | 1891 CIF_LOCK(ifp->if_carp); 1892 IFNET_FOREACH_CARP(ifp, sc) { 1893 CARP_LOCK(sc); 1894 carp_sc_state(sc); 1895 CARP_UNLOCK(sc); 1896 } 1897 CIF_UNLOCK(ifp->if_carp); |
2268} 2269 2270static void | 1898} 1899 1900static void |
2271carp_sc_state_locked(struct carp_softc *sc) | 1901carp_sc_state(struct carp_softc *sc) |
2272{ | 1902{ |
2273 CARP_SCLOCK_ASSERT(sc); | |
2274 | 1903 |
1904 CARP_LOCK_ASSERT(sc); 1905 |
|
2275 if (sc->sc_carpdev->if_link_state != LINK_STATE_UP || 2276 !(sc->sc_carpdev->if_flags & IFF_UP)) { | 1906 if (sc->sc_carpdev->if_link_state != LINK_STATE_UP || 1907 !(sc->sc_carpdev->if_flags & IFF_UP)) { |
2277 sc->sc_flags_backup = SC2IFP(sc)->if_flags; 2278 SC2IFP(sc)->if_flags &= ~IFF_UP; 2279 SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; | |
2280 callout_stop(&sc->sc_ad_tmo); | 1908 callout_stop(&sc->sc_ad_tmo); |
1909#ifdef INET |
|
2281 callout_stop(&sc->sc_md_tmo); | 1910 callout_stop(&sc->sc_md_tmo); |
1911#endif 1912#ifdef INET6 |
|
2282 callout_stop(&sc->sc_md6_tmo); | 1913 callout_stop(&sc->sc_md6_tmo); |
1914#endif |
|
2283 carp_set_state(sc, INIT); 2284 carp_setrun(sc, 0); 2285 if (!sc->sc_suppress) { 2286 carp_suppress_preempt++; | 1915 carp_set_state(sc, INIT); 1916 carp_setrun(sc, 0); 1917 if (!sc->sc_suppress) { 1918 carp_suppress_preempt++; |
2287 if (carp_suppress_preempt == 1) { 2288 CARP_SCUNLOCK(sc); 2289 carp_send_ad_all(); 2290 CARP_SCLOCK(sc); 2291 } | 1919 if (carp_suppress_preempt == 1) 1920 carp_send_ad_all(sc); |
2292 } 2293 sc->sc_suppress = 1; 2294 } else { | 1921 } 1922 sc->sc_suppress = 1; 1923 } else { |
2295 SC2IFP(sc)->if_flags |= sc->sc_flags_backup; | |
2296 carp_set_state(sc, INIT); 2297 carp_setrun(sc, 0); 2298 if (sc->sc_suppress) 2299 carp_suppress_preempt--; 2300 sc->sc_suppress = 0; 2301 } | 1924 carp_set_state(sc, INIT); 1925 carp_setrun(sc, 0); 1926 if (sc->sc_suppress) 1927 carp_suppress_preempt--; 1928 sc->sc_suppress = 0; 1929 } |
2302 2303 return; | |
2304} 2305 | 1930} 1931 |
1932 |
|
2306#ifdef INET 2307extern struct domain inetdomain; 2308static struct protosw in_carp_protosw = { 2309 .pr_type = SOCK_RAW, 2310 .pr_domain = &inetdomain, 2311 .pr_protocol = IPPROTO_CARP, 2312 .pr_flags = PR_ATOMIC|PR_ADDR, 2313 .pr_input = carp_input, --- 16 unchanged lines hidden (view full) --- 2330 .pr_usrreqs = &rip6_usrreqs 2331}; 2332#endif 2333 2334static void 2335carp_mod_cleanup(void) 2336{ 2337 | 1933#ifdef INET 1934extern struct domain inetdomain; 1935static struct protosw in_carp_protosw = { 1936 .pr_type = SOCK_RAW, 1937 .pr_domain = &inetdomain, 1938 .pr_protocol = IPPROTO_CARP, 1939 .pr_flags = PR_ATOMIC|PR_ADDR, 1940 .pr_input = carp_input, --- 16 unchanged lines hidden (view full) --- 1957 .pr_usrreqs = &rip6_usrreqs 1958}; 1959#endif 1960 1961static void 1962carp_mod_cleanup(void) 1963{ 1964 |
2338 if (if_detach_event_tag == NULL) 2339 return; 2340 EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag); 2341 if_clone_detach(&carp_cloner); | |
2342#ifdef INET 2343 if (proto_reg[CARP_INET] == 0) { 2344 (void)ipproto_unregister(IPPROTO_CARP); 2345 pf_proto_unregister(PF_INET, IPPROTO_CARP, SOCK_RAW); 2346 proto_reg[CARP_INET] = -1; 2347 } 2348 carp_iamatch_p = NULL; 2349#endif 2350#ifdef INET6 2351 if (proto_reg[CARP_INET6] == 0) { 2352 (void)ip6proto_unregister(IPPROTO_CARP); 2353 pf_proto_unregister(PF_INET6, IPPROTO_CARP, SOCK_RAW); 2354 proto_reg[CARP_INET6] = -1; 2355 } 2356 carp_iamatch6_p = NULL; 2357 carp_macmatch6_p = NULL; 2358#endif | 1965#ifdef INET 1966 if (proto_reg[CARP_INET] == 0) { 1967 (void)ipproto_unregister(IPPROTO_CARP); 1968 pf_proto_unregister(PF_INET, IPPROTO_CARP, SOCK_RAW); 1969 proto_reg[CARP_INET] = -1; 1970 } 1971 carp_iamatch_p = NULL; 1972#endif 1973#ifdef INET6 1974 if (proto_reg[CARP_INET6] == 0) { 1975 (void)ip6proto_unregister(IPPROTO_CARP); 1976 pf_proto_unregister(PF_INET6, IPPROTO_CARP, SOCK_RAW); 1977 proto_reg[CARP_INET6] = -1; 1978 } 1979 carp_iamatch6_p = NULL; 1980 carp_macmatch6_p = NULL; 1981#endif |
1982 carp_ioctl_p = NULL; 1983 carp_attach_p = NULL; 1984 carp_detach_p = NULL; 1985 carp_get_vhid_p = NULL; |
|
2359 carp_linkstate_p = NULL; 2360 carp_forus_p = NULL; 2361 carp_output_p = NULL; 2362 mtx_destroy(&carp_mtx); 2363} 2364 2365static int 2366carp_mod_load(void) 2367{ 2368 int err; 2369 | 1986 carp_linkstate_p = NULL; 1987 carp_forus_p = NULL; 1988 carp_output_p = NULL; 1989 mtx_destroy(&carp_mtx); 1990} 1991 1992static int 1993carp_mod_load(void) 1994{ 1995 int err; 1996 |
2370 if_detach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, 2371 carp_ifdetach, NULL, EVENTHANDLER_PRI_ANY); 2372 if (if_detach_event_tag == NULL) 2373 return (ENOMEM); | |
2374 mtx_init(&carp_mtx, "carp_mtx", NULL, MTX_DEF); | 1997 mtx_init(&carp_mtx, "carp_mtx", NULL, MTX_DEF); |
2375 LIST_INIT(&carpif_list); 2376 if_clone_attach(&carp_cloner); 2377 carp_linkstate_p = carp_carpdev_state; | 1998 LIST_INIT(&carp_list); 1999 carp_get_vhid_p = carp_get_vhid; |
2378 carp_forus_p = carp_forus; 2379 carp_output_p = carp_output; | 2000 carp_forus_p = carp_forus; 2001 carp_output_p = carp_output; |
2002 carp_linkstate_p = carp_linkstate; 2003 carp_ioctl_p = carp_ioctl; 2004 carp_attach_p = carp_attach; 2005 carp_detach_p = carp_detach; |
|
2380#ifdef INET6 2381 carp_iamatch6_p = carp_iamatch6; 2382 carp_macmatch6_p = carp_macmatch6; 2383 proto_reg[CARP_INET6] = pf_proto_register(PF_INET6, 2384 (struct protosw *)&in6_carp_protosw); | 2006#ifdef INET6 2007 carp_iamatch6_p = carp_iamatch6; 2008 carp_macmatch6_p = carp_macmatch6; 2009 proto_reg[CARP_INET6] = pf_proto_register(PF_INET6, 2010 (struct protosw *)&in6_carp_protosw); |
2385 if (proto_reg[CARP_INET6] != 0) { | 2011 if (proto_reg[CARP_INET6]) { |
2386 printf("carp: error %d attaching to PF_INET6\n", 2387 proto_reg[CARP_INET6]); 2388 carp_mod_cleanup(); 2389 return (proto_reg[CARP_INET6]); 2390 } 2391 err = ip6proto_register(IPPROTO_CARP); 2392 if (err) { 2393 printf("carp: error %d registering with INET6\n", err); 2394 carp_mod_cleanup(); 2395 return (err); 2396 } 2397#endif 2398#ifdef INET 2399 carp_iamatch_p = carp_iamatch; 2400 proto_reg[CARP_INET] = pf_proto_register(PF_INET, &in_carp_protosw); | 2012 printf("carp: error %d attaching to PF_INET6\n", 2013 proto_reg[CARP_INET6]); 2014 carp_mod_cleanup(); 2015 return (proto_reg[CARP_INET6]); 2016 } 2017 err = ip6proto_register(IPPROTO_CARP); 2018 if (err) { 2019 printf("carp: error %d registering with INET6\n", err); 2020 carp_mod_cleanup(); 2021 return (err); 2022 } 2023#endif 2024#ifdef INET 2025 carp_iamatch_p = carp_iamatch; 2026 proto_reg[CARP_INET] = pf_proto_register(PF_INET, &in_carp_protosw); |
2401 if (proto_reg[CARP_INET] != 0) { | 2027 if (proto_reg[CARP_INET]) { |
2402 printf("carp: error %d attaching to PF_INET\n", 2403 proto_reg[CARP_INET]); 2404 carp_mod_cleanup(); 2405 return (proto_reg[CARP_INET]); 2406 } 2407 err = ipproto_register(IPPROTO_CARP); 2408 if (err) { 2409 printf("carp: error %d registering with INET\n", err); 2410 carp_mod_cleanup(); 2411 return (err); 2412 } 2413#endif | 2028 printf("carp: error %d attaching to PF_INET\n", 2029 proto_reg[CARP_INET]); 2030 carp_mod_cleanup(); 2031 return (proto_reg[CARP_INET]); 2032 } 2033 err = ipproto_register(IPPROTO_CARP); 2034 if (err) { 2035 printf("carp: error %d registering with INET\n", err); 2036 carp_mod_cleanup(); 2037 return (err); 2038 } 2039#endif |
2414 return 0; | 2040 return (0); |
2415} 2416 2417static int 2418carp_modevent(module_t mod, int type, void *data) 2419{ 2420 switch (type) { 2421 case MOD_LOAD: 2422 return carp_mod_load(); 2423 /* NOTREACHED */ 2424 case MOD_UNLOAD: | 2041} 2042 2043static int 2044carp_modevent(module_t mod, int type, void *data) 2045{ 2046 switch (type) { 2047 case MOD_LOAD: 2048 return carp_mod_load(); 2049 /* NOTREACHED */ 2050 case MOD_UNLOAD: |
2425 /* 2426 * XXX: For now, disallow module unloading by default due to 2427 * a race condition where a thread may dereference one of the 2428 * function pointer hooks after the module has been 2429 * unloaded, during processing of a packet, causing a panic. 2430 */ 2431#ifdef CARPMOD_CAN_UNLOAD 2432 carp_mod_cleanup(); 2433#else 2434 return (EBUSY); 2435#endif | 2051 mtx_lock(&carp_mtx); 2052 if (LIST_EMPTY(&carp_list)) 2053 carp_mod_cleanup(); 2054 else { 2055 mtx_unlock(&carp_mtx); 2056 return (EBUSY); 2057 } |
2436 break; 2437 2438 default: 2439 return (EINVAL); 2440 } 2441 2442 return (0); 2443} 2444 2445static moduledata_t carp_mod = { 2446 "carp", 2447 carp_modevent, 2448 0 2449}; 2450 2451DECLARE_MODULE(carp, carp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); | 2058 break; 2059 2060 default: 2061 return (EINVAL); 2062 } 2063 2064 return (0); 2065} 2066 2067static moduledata_t carp_mod = { 2068 "carp", 2069 carp_modevent, 2070 0 2071}; 2072 2073DECLARE_MODULE(carp, carp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); |