1 1.121 rin /* $NetBSD: ip_carp.c,v 1.121 2024/12/20 00:49:08 rin Exp $ */ 2 1.1 liamjfoy /* $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $ */ 3 1.1 liamjfoy 4 1.1 liamjfoy /* 5 1.1 liamjfoy * Copyright (c) 2002 Michael Shalayeff. All rights reserved. 6 1.1 liamjfoy * Copyright (c) 2003 Ryan McBride. All rights reserved. 7 1.1 liamjfoy * 8 1.1 liamjfoy * Redistribution and use in source and binary forms, with or without 9 1.1 liamjfoy * modification, are permitted provided that the following conditions 10 1.1 liamjfoy * are met: 11 1.1 liamjfoy * 1. Redistributions of source code must retain the above copyright 12 1.1 liamjfoy * notice, this list of conditions and the following disclaimer. 13 1.1 liamjfoy * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 liamjfoy * notice, this list of conditions and the following disclaimer in the 15 1.1 liamjfoy * documentation and/or other materials provided with the distribution. 16 1.1 liamjfoy * 17 1.1 liamjfoy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 1.1 liamjfoy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 1.1 liamjfoy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 liamjfoy * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 21 1.1 liamjfoy * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 1.1 liamjfoy * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 1.1 liamjfoy * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 liamjfoy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 1.1 liamjfoy * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 1.1 liamjfoy * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 1.1 liamjfoy * THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 liamjfoy */ 29 1.1 liamjfoy 30 1.62 pooka #ifdef _KERNEL_OPT 31 1.42 pooka #include "opt_inet.h" 32 1.53 bouyer #include "opt_mbuftrace.h" 33 1.62 pooka #endif 34 1.42 pooka 35 1.20 lukem #include <sys/cdefs.h> 36 1.121 rin __KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.121 2024/12/20 00:49:08 rin Exp $"); 37 1.20 lukem 38 1.1 liamjfoy /* 39 1.1 liamjfoy * TODO: 40 1.1 liamjfoy * - iface reconfigure 41 1.1 liamjfoy * - support for hardware checksum calculations; 42 1.1 liamjfoy * 43 1.1 liamjfoy */ 44 1.1 liamjfoy 45 1.1 liamjfoy #include <sys/param.h> 46 1.1 liamjfoy #include <sys/proc.h> 47 1.1 liamjfoy #include <sys/mbuf.h> 48 1.1 liamjfoy #include <sys/socket.h> 49 1.1 liamjfoy #include <sys/socketvar.h> 50 1.1 liamjfoy #include <sys/callout.h> 51 1.1 liamjfoy #include <sys/ioctl.h> 52 1.1 liamjfoy #include <sys/errno.h> 53 1.1 liamjfoy #include <sys/device.h> 54 1.1 liamjfoy #include <sys/time.h> 55 1.1 liamjfoy #include <sys/kernel.h> 56 1.1 liamjfoy #include <sys/kauth.h> 57 1.1 liamjfoy #include <sys/sysctl.h> 58 1.1 liamjfoy #include <sys/ucred.h> 59 1.1 liamjfoy #include <sys/syslog.h> 60 1.1 liamjfoy #include <sys/acct.h> 61 1.47 tls #include <sys/cprng.h> 62 1.18 ad #include <sys/cpu.h> 63 1.93 ozaki #include <sys/pserialize.h> 64 1.93 ozaki #include <sys/psref.h> 65 1.1 liamjfoy 66 1.1 liamjfoy #include <net/if.h> 67 1.1 liamjfoy #include <net/pfil.h> 68 1.1 liamjfoy #include <net/if_types.h> 69 1.1 liamjfoy #include <net/if_ether.h> 70 1.1 liamjfoy #include <net/route.h> 71 1.25 thorpej #include <net/net_stats.h> 72 1.1 liamjfoy #include <netinet/if_inarp.h> 73 1.84 ozaki #include <netinet/wqinput.h> 74 1.1 liamjfoy 75 1.1 liamjfoy #ifdef INET 76 1.1 liamjfoy #include <netinet/in.h> 77 1.1 liamjfoy #include <netinet/in_systm.h> 78 1.1 liamjfoy #include <netinet/in_var.h> 79 1.1 liamjfoy #include <netinet/ip.h> 80 1.1 liamjfoy #include <netinet/ip_var.h> 81 1.1 liamjfoy 82 1.1 liamjfoy #include <net/if_dl.h> 83 1.1 liamjfoy #endif 84 1.1 liamjfoy 85 1.1 liamjfoy #ifdef INET6 86 1.1 liamjfoy #include <netinet/icmp6.h> 87 1.1 liamjfoy #include <netinet/ip6.h> 88 1.1 liamjfoy #include <netinet6/ip6_var.h> 89 1.1 liamjfoy #include <netinet6/nd6.h> 90 1.23 ws #include <netinet6/scope6_var.h> 91 1.76 is #include <netinet6/in6_var.h> 92 1.1 liamjfoy #endif 93 1.1 liamjfoy 94 1.1 liamjfoy #include <net/bpf.h> 95 1.1 liamjfoy 96 1.1 liamjfoy #include <sys/sha1.h> 97 1.1 liamjfoy 98 1.1 liamjfoy #include <netinet/ip_carp.h> 99 1.1 liamjfoy 100 1.61 christos #include "ioconf.h" 101 1.61 christos 102 1.1 liamjfoy struct carp_mc_entry { 103 1.1 liamjfoy LIST_ENTRY(carp_mc_entry) mc_entries; 104 1.1 liamjfoy union { 105 1.1 liamjfoy struct ether_multi *mcu_enm; 106 1.1 liamjfoy } mc_u; 107 1.1 liamjfoy struct sockaddr_storage mc_addr; 108 1.1 liamjfoy }; 109 1.1 liamjfoy #define mc_enm mc_u.mcu_enm 110 1.1 liamjfoy 111 1.1 liamjfoy struct carp_softc { 112 1.1 liamjfoy struct ethercom sc_ac; 113 1.1 liamjfoy #define sc_if sc_ac.ec_if 114 1.1 liamjfoy #define sc_carpdev sc_ac.ec_if.if_carpdev 115 1.116 yamaguch void *sc_linkstate_hook; 116 1.1 liamjfoy int ah_cookie; 117 1.1 liamjfoy int lh_cookie; 118 1.1 liamjfoy struct ip_moptions sc_imo; 119 1.1 liamjfoy #ifdef INET6 120 1.1 liamjfoy struct ip6_moptions sc_im6o; 121 1.1 liamjfoy #endif /* INET6 */ 122 1.1 liamjfoy TAILQ_ENTRY(carp_softc) sc_list; 123 1.1 liamjfoy 124 1.1 liamjfoy enum { INIT = 0, BACKUP, MASTER } sc_state; 125 1.1 liamjfoy 126 1.1 liamjfoy int sc_suppress; 127 1.1 liamjfoy int sc_bow_out; 128 1.1 liamjfoy 129 1.1 liamjfoy int sc_sendad_errors; 130 1.1 liamjfoy #define CARP_SENDAD_MAX_ERRORS 3 131 1.1 liamjfoy int sc_sendad_success; 132 1.1 liamjfoy #define CARP_SENDAD_MIN_SUCCESS 3 133 1.1 liamjfoy 134 1.1 liamjfoy int sc_vhid; 135 1.1 liamjfoy int sc_advskew; 136 1.1 liamjfoy int sc_naddrs; 137 1.1 liamjfoy int sc_naddrs6; 138 1.1 liamjfoy int sc_advbase; /* seconds */ 139 1.1 liamjfoy int sc_init_counter; 140 1.1 liamjfoy u_int64_t sc_counter; 141 1.1 liamjfoy 142 1.1 liamjfoy /* authentication */ 143 1.1 liamjfoy #define CARP_HMAC_PAD 64 144 1.1 liamjfoy unsigned char sc_key[CARP_KEY_LEN]; 145 1.1 liamjfoy unsigned char sc_pad[CARP_HMAC_PAD]; 146 1.1 liamjfoy SHA1_CTX sc_sha1; 147 1.1 liamjfoy u_int32_t sc_hashkey[2]; 148 1.1 liamjfoy 149 1.1 liamjfoy struct callout sc_ad_tmo; /* advertisement timeout */ 150 1.1 liamjfoy struct callout sc_md_tmo; /* master down timeout */ 151 1.1 liamjfoy struct callout sc_md6_tmo; /* master down timeout */ 152 1.1 liamjfoy 153 1.1 liamjfoy LIST_HEAD(__carp_mchead, carp_mc_entry) carp_mc_listhead; 154 1.1 liamjfoy }; 155 1.1 liamjfoy 156 1.59 ozaki int carp_suppress_preempt = 0; 157 1.58 ozaki static int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0, 0 }; /* XXX for now */ 158 1.24 thorpej 159 1.24 thorpej static percpu_t *carpstat_percpu; 160 1.24 thorpej 161 1.25 thorpej #define CARP_STATINC(x) _NET_STATINC(carpstat_percpu, x) 162 1.1 liamjfoy 163 1.53 bouyer #ifdef MBUFTRACE 164 1.53 bouyer static struct mowner carp_proto_mowner_rx = MOWNER_INIT("carp", "rx"); 165 1.53 bouyer static struct mowner carp_proto_mowner_tx = MOWNER_INIT("carp", "tx"); 166 1.53 bouyer static struct mowner carp_proto6_mowner_rx = MOWNER_INIT("carp6", "rx"); 167 1.53 bouyer static struct mowner carp_proto6_mowner_tx = MOWNER_INIT("carp6", "tx"); 168 1.53 bouyer #endif 169 1.53 bouyer 170 1.1 liamjfoy struct carp_if { 171 1.1 liamjfoy TAILQ_HEAD(, carp_softc) vhif_vrs; 172 1.1 liamjfoy int vhif_nvrs; 173 1.1 liamjfoy 174 1.1 liamjfoy struct ifnet *vhif_ifp; 175 1.1 liamjfoy }; 176 1.1 liamjfoy 177 1.1 liamjfoy #define CARP_LOG(sc, s) \ 178 1.1 liamjfoy if (carp_opts[CARPCTL_LOG]) { \ 179 1.1 liamjfoy if (sc) \ 180 1.1 liamjfoy log(LOG_INFO, "%s: ", \ 181 1.1 liamjfoy (sc)->sc_if.if_xname); \ 182 1.1 liamjfoy else \ 183 1.1 liamjfoy log(LOG_INFO, "carp: "); \ 184 1.1 liamjfoy addlog s; \ 185 1.1 liamjfoy addlog("\n"); \ 186 1.1 liamjfoy } 187 1.1 liamjfoy 188 1.58 ozaki static void carp_hmac_prepare(struct carp_softc *); 189 1.120 mrg static void carp_hmac_generate(struct carp_softc *, u_int32_t[2], 190 1.120 mrg unsigned char[20]); 191 1.120 mrg static int carp_hmac_verify(struct carp_softc *, u_int32_t[2], 192 1.120 mrg unsigned char[20]); 193 1.58 ozaki static void carp_setroute(struct carp_softc *, int); 194 1.58 ozaki static void carp_proto_input_c(struct mbuf *, struct carp_header *, 195 1.58 ozaki sa_family_t); 196 1.58 ozaki static void carpdetach(struct carp_softc *); 197 1.95 maxv static void carp_prepare_ad(struct mbuf *, struct carp_softc *, 198 1.58 ozaki struct carp_header *); 199 1.58 ozaki static void carp_send_ad_all(void); 200 1.58 ozaki static void carp_send_ad(void *); 201 1.58 ozaki static void carp_send_arp(struct carp_softc *); 202 1.58 ozaki static void carp_master_down(void *); 203 1.58 ozaki static int carp_ioctl(struct ifnet *, u_long, void *); 204 1.58 ozaki static void carp_start(struct ifnet *); 205 1.58 ozaki static void carp_setrun(struct carp_softc *, sa_family_t); 206 1.58 ozaki static void carp_set_state(struct carp_softc *, int); 207 1.58 ozaki static int carp_addrcount(struct carp_if *, struct in_ifaddr *, int); 208 1.1 liamjfoy enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING }; 209 1.1 liamjfoy 210 1.58 ozaki static void carp_multicast_cleanup(struct carp_softc *); 211 1.58 ozaki static int carp_set_ifp(struct carp_softc *, struct ifnet *); 212 1.58 ozaki static void carp_set_enaddr(struct carp_softc *); 213 1.58 ozaki #if 0 214 1.58 ozaki static void carp_addr_updated(void *); 215 1.58 ozaki #endif 216 1.58 ozaki static u_int32_t carp_hash(struct carp_softc *, u_char *); 217 1.58 ozaki static int carp_set_addr(struct carp_softc *, struct sockaddr_in *); 218 1.58 ozaki static int carp_join_multicast(struct carp_softc *); 219 1.1 liamjfoy #ifdef INET6 220 1.58 ozaki static void carp_send_na(struct carp_softc *); 221 1.58 ozaki static int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *); 222 1.58 ozaki static int carp_join_multicast6(struct carp_softc *); 223 1.1 liamjfoy #endif 224 1.58 ozaki static int carp_clone_create(struct if_clone *, int); 225 1.58 ozaki static int carp_clone_destroy(struct ifnet *); 226 1.58 ozaki static int carp_ether_addmulti(struct carp_softc *, struct ifreq *); 227 1.58 ozaki static int carp_ether_delmulti(struct carp_softc *, struct ifreq *); 228 1.58 ozaki static void carp_ether_purgemulti(struct carp_softc *); 229 1.105 kardel static void carp_update_link_state(struct carp_softc *sc); 230 1.1 liamjfoy 231 1.58 ozaki static void sysctl_net_inet_carp_setup(struct sysctllog **); 232 1.39 pooka 233 1.84 ozaki /* workqueue-based pr_input */ 234 1.84 ozaki static struct wqinput *carp_wqinput; 235 1.84 ozaki static void _carp_proto_input(struct mbuf *, int, int); 236 1.84 ozaki #ifdef INET6 237 1.84 ozaki static struct wqinput *carp6_wqinput; 238 1.84 ozaki static void _carp6_proto_input(struct mbuf *, int, int); 239 1.84 ozaki #endif 240 1.84 ozaki 241 1.1 liamjfoy struct if_clone carp_cloner = 242 1.1 liamjfoy IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy); 243 1.1 liamjfoy 244 1.1 liamjfoy static __inline u_int16_t 245 1.1 liamjfoy carp_cksum(struct mbuf *m, int len) 246 1.1 liamjfoy { 247 1.1 liamjfoy return (in_cksum(m, len)); 248 1.1 liamjfoy } 249 1.1 liamjfoy 250 1.103 joerg #ifdef INET6 251 1.85 ozaki static __inline u_int16_t 252 1.85 ozaki carp6_cksum(struct mbuf *m, uint32_t off, uint32_t len) 253 1.85 ozaki { 254 1.85 ozaki return (in6_cksum(m, IPPROTO_CARP, off, len)); 255 1.85 ozaki } 256 1.103 joerg #endif 257 1.85 ozaki 258 1.58 ozaki static void 259 1.1 liamjfoy carp_hmac_prepare(struct carp_softc *sc) 260 1.1 liamjfoy { 261 1.1 liamjfoy u_int8_t carp_version = CARP_VERSION, type = CARP_ADVERTISEMENT; 262 1.1 liamjfoy u_int8_t vhid = sc->sc_vhid & 0xff; 263 1.1 liamjfoy SHA1_CTX sha1ctx; 264 1.1 liamjfoy u_int32_t kmd[5]; 265 1.1 liamjfoy struct ifaddr *ifa; 266 1.1 liamjfoy int i, found; 267 1.1 liamjfoy struct in_addr last, cur, in; 268 1.1 liamjfoy #ifdef INET6 269 1.1 liamjfoy struct in6_addr last6, cur6, in6; 270 1.1 liamjfoy #endif /* INET6 */ 271 1.1 liamjfoy 272 1.1 liamjfoy /* compute ipad from key */ 273 1.32 cegger memset(sc->sc_pad, 0, sizeof(sc->sc_pad)); 274 1.34 tsutsui memcpy(sc->sc_pad, sc->sc_key, sizeof(sc->sc_key)); 275 1.1 liamjfoy for (i = 0; i < sizeof(sc->sc_pad); i++) 276 1.1 liamjfoy sc->sc_pad[i] ^= 0x36; 277 1.1 liamjfoy 278 1.1 liamjfoy /* precompute first part of inner hash */ 279 1.1 liamjfoy SHA1Init(&sc->sc_sha1); 280 1.1 liamjfoy SHA1Update(&sc->sc_sha1, sc->sc_pad, sizeof(sc->sc_pad)); 281 1.1 liamjfoy SHA1Update(&sc->sc_sha1, (void *)&carp_version, sizeof(carp_version)); 282 1.1 liamjfoy SHA1Update(&sc->sc_sha1, (void *)&type, sizeof(type)); 283 1.1 liamjfoy 284 1.1 liamjfoy /* generate a key for the arpbalance hash, before the vhid is hashed */ 285 1.34 tsutsui memcpy(&sha1ctx, &sc->sc_sha1, sizeof(sha1ctx)); 286 1.1 liamjfoy SHA1Final((unsigned char *)kmd, &sha1ctx); 287 1.1 liamjfoy sc->sc_hashkey[0] = kmd[0] ^ kmd[1]; 288 1.1 liamjfoy sc->sc_hashkey[1] = kmd[2] ^ kmd[3]; 289 1.1 liamjfoy 290 1.1 liamjfoy /* the rest of the precomputation */ 291 1.1 liamjfoy SHA1Update(&sc->sc_sha1, (void *)&vhid, sizeof(vhid)); 292 1.1 liamjfoy 293 1.1 liamjfoy /* Hash the addresses from smallest to largest, not interface order */ 294 1.1 liamjfoy #ifdef INET 295 1.1 liamjfoy cur.s_addr = 0; 296 1.1 liamjfoy do { 297 1.93 ozaki int s; 298 1.1 liamjfoy found = 0; 299 1.1 liamjfoy last = cur; 300 1.1 liamjfoy cur.s_addr = 0xffffffff; 301 1.93 ozaki s = pserialize_read_enter(); 302 1.74 ozaki IFADDR_READER_FOREACH(ifa, &sc->sc_if) { 303 1.1 liamjfoy in.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; 304 1.1 liamjfoy if (ifa->ifa_addr->sa_family == AF_INET && 305 1.1 liamjfoy ntohl(in.s_addr) > ntohl(last.s_addr) && 306 1.1 liamjfoy ntohl(in.s_addr) < ntohl(cur.s_addr)) { 307 1.1 liamjfoy cur.s_addr = in.s_addr; 308 1.1 liamjfoy found++; 309 1.1 liamjfoy } 310 1.1 liamjfoy } 311 1.93 ozaki pserialize_read_exit(s); 312 1.1 liamjfoy if (found) 313 1.1 liamjfoy SHA1Update(&sc->sc_sha1, (void *)&cur, sizeof(cur)); 314 1.1 liamjfoy } while (found); 315 1.1 liamjfoy #endif /* INET */ 316 1.1 liamjfoy 317 1.1 liamjfoy #ifdef INET6 318 1.1 liamjfoy memset(&cur6, 0x00, sizeof(cur6)); 319 1.1 liamjfoy do { 320 1.93 ozaki int s; 321 1.1 liamjfoy found = 0; 322 1.1 liamjfoy last6 = cur6; 323 1.1 liamjfoy memset(&cur6, 0xff, sizeof(cur6)); 324 1.93 ozaki s = pserialize_read_enter(); 325 1.74 ozaki IFADDR_READER_FOREACH(ifa, &sc->sc_if) { 326 1.1 liamjfoy in6 = ifatoia6(ifa)->ia_addr.sin6_addr; 327 1.1 liamjfoy if (IN6_IS_ADDR_LINKLOCAL(&in6)) 328 1.1 liamjfoy in6.s6_addr16[1] = 0; 329 1.1 liamjfoy if (ifa->ifa_addr->sa_family == AF_INET6 && 330 1.1 liamjfoy memcmp(&in6, &last6, sizeof(in6)) > 0 && 331 1.1 liamjfoy memcmp(&in6, &cur6, sizeof(in6)) < 0) { 332 1.1 liamjfoy cur6 = in6; 333 1.1 liamjfoy found++; 334 1.1 liamjfoy } 335 1.1 liamjfoy } 336 1.93 ozaki pserialize_read_exit(s); 337 1.1 liamjfoy if (found) 338 1.1 liamjfoy SHA1Update(&sc->sc_sha1, (void *)&cur6, sizeof(cur6)); 339 1.1 liamjfoy } while (found); 340 1.1 liamjfoy #endif /* INET6 */ 341 1.1 liamjfoy 342 1.1 liamjfoy /* convert ipad to opad */ 343 1.1 liamjfoy for (i = 0; i < sizeof(sc->sc_pad); i++) 344 1.1 liamjfoy sc->sc_pad[i] ^= 0x36 ^ 0x5c; 345 1.1 liamjfoy } 346 1.1 liamjfoy 347 1.58 ozaki static void 348 1.1 liamjfoy carp_hmac_generate(struct carp_softc *sc, u_int32_t counter[2], 349 1.1 liamjfoy unsigned char md[20]) 350 1.1 liamjfoy { 351 1.1 liamjfoy SHA1_CTX sha1ctx; 352 1.1 liamjfoy 353 1.1 liamjfoy /* fetch first half of inner hash */ 354 1.34 tsutsui memcpy(&sha1ctx, &sc->sc_sha1, sizeof(sha1ctx)); 355 1.1 liamjfoy 356 1.1 liamjfoy SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter)); 357 1.1 liamjfoy SHA1Final(md, &sha1ctx); 358 1.1 liamjfoy 359 1.1 liamjfoy /* outer hash */ 360 1.1 liamjfoy SHA1Init(&sha1ctx); 361 1.1 liamjfoy SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad)); 362 1.1 liamjfoy SHA1Update(&sha1ctx, md, 20); 363 1.1 liamjfoy SHA1Final(md, &sha1ctx); 364 1.1 liamjfoy } 365 1.1 liamjfoy 366 1.58 ozaki static int 367 1.1 liamjfoy carp_hmac_verify(struct carp_softc *sc, u_int32_t counter[2], 368 1.1 liamjfoy unsigned char md[20]) 369 1.1 liamjfoy { 370 1.1 liamjfoy unsigned char md2[20]; 371 1.1 liamjfoy 372 1.1 liamjfoy carp_hmac_generate(sc, counter, md2); 373 1.1 liamjfoy 374 1.31 cegger return (memcmp(md, md2, sizeof(md2))); 375 1.1 liamjfoy } 376 1.1 liamjfoy 377 1.58 ozaki static void 378 1.1 liamjfoy carp_setroute(struct carp_softc *sc, int cmd) 379 1.1 liamjfoy { 380 1.1 liamjfoy struct ifaddr *ifa; 381 1.93 ozaki int s, bound; 382 1.1 liamjfoy 383 1.54 bouyer KERNEL_LOCK(1, NULL); 384 1.93 ozaki bound = curlwp_bind(); 385 1.93 ozaki s = pserialize_read_enter(); 386 1.74 ozaki IFADDR_READER_FOREACH(ifa, &sc->sc_if) { 387 1.93 ozaki struct psref psref; 388 1.93 ozaki ifa_acquire(ifa, &psref); 389 1.93 ozaki pserialize_read_exit(s); 390 1.93 ozaki 391 1.1 liamjfoy switch (ifa->ifa_addr->sa_family) { 392 1.1 liamjfoy case AF_INET: { 393 1.1 liamjfoy int count = 0; 394 1.1 liamjfoy struct rtentry *rt; 395 1.1 liamjfoy int hr_otherif, nr_ourif; 396 1.1 liamjfoy 397 1.1 liamjfoy /* 398 1.1 liamjfoy * Avoid screwing with the routes if there are other 399 1.1 liamjfoy * carp interfaces which are master and have the same 400 1.1 liamjfoy * address. 401 1.1 liamjfoy */ 402 1.1 liamjfoy if (sc->sc_carpdev != NULL && 403 1.1 liamjfoy sc->sc_carpdev->if_carp != NULL) { 404 1.1 liamjfoy count = carp_addrcount( 405 1.1 liamjfoy (struct carp_if *)sc->sc_carpdev->if_carp, 406 1.1 liamjfoy ifatoia(ifa), CARP_COUNT_MASTER); 407 1.1 liamjfoy if ((cmd == RTM_ADD && count != 1) || 408 1.1 liamjfoy (cmd == RTM_DELETE && count != 0)) 409 1.102 ozaki goto next; 410 1.1 liamjfoy } 411 1.1 liamjfoy 412 1.1 liamjfoy /* Remove the existing host route, if any */ 413 1.1 liamjfoy rtrequest(RTM_DELETE, ifa->ifa_addr, 414 1.1 liamjfoy ifa->ifa_addr, ifa->ifa_netmask, 415 1.1 liamjfoy RTF_HOST, NULL); 416 1.1 liamjfoy 417 1.14 dyoung rt = NULL; 418 1.14 dyoung (void)rtrequest(RTM_GET, ifa->ifa_addr, ifa->ifa_addr, 419 1.14 dyoung ifa->ifa_netmask, RTF_HOST, &rt); 420 1.1 liamjfoy hr_otherif = (rt && rt->rt_ifp != &sc->sc_if && 421 1.63 ozaki (rt->rt_flags & RTF_CONNECTED)); 422 1.14 dyoung if (rt != NULL) { 423 1.80 ozaki rt_unref(rt); 424 1.14 dyoung rt = NULL; 425 1.14 dyoung } 426 1.1 liamjfoy 427 1.1 liamjfoy /* Check for a network route on our interface */ 428 1.14 dyoung 429 1.14 dyoung rt = NULL; 430 1.14 dyoung (void)rtrequest(RTM_GET, ifa->ifa_addr, ifa->ifa_addr, 431 1.14 dyoung ifa->ifa_netmask, 0, &rt); 432 1.1 liamjfoy nr_ourif = (rt && rt->rt_ifp == &sc->sc_if); 433 1.1 liamjfoy 434 1.1 liamjfoy switch (cmd) { 435 1.1 liamjfoy case RTM_ADD: 436 1.1 liamjfoy if (hr_otherif) { 437 1.1 liamjfoy ifa->ifa_rtrequest = NULL; 438 1.63 ozaki ifa->ifa_flags &= ~RTF_CONNECTED; 439 1.1 liamjfoy 440 1.1 liamjfoy rtrequest(RTM_ADD, ifa->ifa_addr, 441 1.1 liamjfoy ifa->ifa_addr, ifa->ifa_netmask, 442 1.1 liamjfoy RTF_UP | RTF_HOST, NULL); 443 1.1 liamjfoy } 444 1.1 liamjfoy if (!hr_otherif || nr_ourif || !rt) { 445 1.63 ozaki if (nr_ourif && 446 1.63 ozaki (rt->rt_flags & RTF_CONNECTED) == 0) 447 1.14 dyoung rtrequest(RTM_DELETE, 448 1.14 dyoung ifa->ifa_addr, 449 1.1 liamjfoy ifa->ifa_addr, 450 1.1 liamjfoy ifa->ifa_netmask, 0, NULL); 451 1.1 liamjfoy 452 1.1 liamjfoy ifa->ifa_rtrequest = arp_rtrequest; 453 1.63 ozaki ifa->ifa_flags |= RTF_CONNECTED; 454 1.1 liamjfoy 455 1.1 liamjfoy if (rtrequest(RTM_ADD, ifa->ifa_addr, 456 1.1 liamjfoy ifa->ifa_addr, ifa->ifa_netmask, 0, 457 1.1 liamjfoy NULL) == 0) 458 1.1 liamjfoy ifa->ifa_flags |= IFA_ROUTE; 459 1.1 liamjfoy } 460 1.1 liamjfoy break; 461 1.1 liamjfoy case RTM_DELETE: 462 1.1 liamjfoy break; 463 1.1 liamjfoy default: 464 1.1 liamjfoy break; 465 1.1 liamjfoy } 466 1.14 dyoung if (rt != NULL) { 467 1.80 ozaki rt_unref(rt); 468 1.14 dyoung rt = NULL; 469 1.14 dyoung } 470 1.1 liamjfoy break; 471 1.1 liamjfoy } 472 1.1 liamjfoy 473 1.1 liamjfoy #ifdef INET6 474 1.1 liamjfoy case AF_INET6: 475 1.1 liamjfoy if (cmd == RTM_ADD) 476 1.60 roy in6_ifaddlocal(ifa); 477 1.1 liamjfoy else 478 1.60 roy in6_ifremlocal(ifa); 479 1.1 liamjfoy break; 480 1.1 liamjfoy #endif /* INET6 */ 481 1.1 liamjfoy default: 482 1.1 liamjfoy break; 483 1.1 liamjfoy } 484 1.102 ozaki next: 485 1.93 ozaki s = pserialize_read_enter(); 486 1.93 ozaki ifa_release(ifa, &psref); 487 1.1 liamjfoy } 488 1.93 ozaki pserialize_read_exit(s); 489 1.93 ozaki curlwp_bindx(bound); 490 1.54 bouyer KERNEL_UNLOCK_ONE(NULL); 491 1.1 liamjfoy } 492 1.1 liamjfoy 493 1.1 liamjfoy /* 494 1.1 liamjfoy * process input packet. 495 1.1 liamjfoy * we have rearranged checks order compared to the rfc, 496 1.1 liamjfoy * but it seems more efficient this way or not possible otherwise. 497 1.1 liamjfoy */ 498 1.84 ozaki static void 499 1.84 ozaki _carp_proto_input(struct mbuf *m, int hlen, int proto) 500 1.1 liamjfoy { 501 1.1 liamjfoy struct ip *ip = mtod(m, struct ip *); 502 1.1 liamjfoy struct carp_softc *sc = NULL; 503 1.1 liamjfoy struct carp_header *ch; 504 1.51 christos int iplen, len; 505 1.67 ozaki struct ifnet *rcvif; 506 1.1 liamjfoy 507 1.24 thorpej CARP_STATINC(CARP_STAT_IPACKETS); 508 1.53 bouyer MCLAIM(m, &carp_proto_mowner_rx); 509 1.1 liamjfoy 510 1.1 liamjfoy if (!carp_opts[CARPCTL_ALLOW]) { 511 1.1 liamjfoy m_freem(m); 512 1.1 liamjfoy return; 513 1.1 liamjfoy } 514 1.1 liamjfoy 515 1.67 ozaki rcvif = m_get_rcvif_NOMPSAFE(m); 516 1.1 liamjfoy /* check if received on a valid carp interface */ 517 1.67 ozaki if (rcvif->if_type != IFT_CARP) { 518 1.24 thorpej CARP_STATINC(CARP_STAT_BADIF); 519 1.1 liamjfoy CARP_LOG(sc, ("packet received on non-carp interface: %s", 520 1.67 ozaki rcvif->if_xname)); 521 1.1 liamjfoy m_freem(m); 522 1.1 liamjfoy return; 523 1.1 liamjfoy } 524 1.1 liamjfoy 525 1.1 liamjfoy /* verify that the IP TTL is 255. */ 526 1.1 liamjfoy if (ip->ip_ttl != CARP_DFLTTL) { 527 1.24 thorpej CARP_STATINC(CARP_STAT_BADTTL); 528 1.1 liamjfoy CARP_LOG(sc, ("received ttl %d != %d on %s", ip->ip_ttl, 529 1.67 ozaki CARP_DFLTTL, rcvif->if_xname)); 530 1.1 liamjfoy m_freem(m); 531 1.1 liamjfoy return; 532 1.1 liamjfoy } 533 1.1 liamjfoy 534 1.1 liamjfoy /* 535 1.1 liamjfoy * verify that the received packet length is 536 1.1 liamjfoy * equal to the CARP header 537 1.1 liamjfoy */ 538 1.1 liamjfoy iplen = ip->ip_hl << 2; 539 1.1 liamjfoy len = iplen + sizeof(*ch); 540 1.1 liamjfoy if (len > m->m_pkthdr.len) { 541 1.24 thorpej CARP_STATINC(CARP_STAT_BADLEN); 542 1.1 liamjfoy CARP_LOG(sc, ("packet too short %d on %s", m->m_pkthdr.len, 543 1.67 ozaki rcvif->if_xname)); 544 1.1 liamjfoy m_freem(m); 545 1.1 liamjfoy return; 546 1.1 liamjfoy } 547 1.1 liamjfoy 548 1.1 liamjfoy if ((m = m_pullup(m, len)) == NULL) { 549 1.24 thorpej CARP_STATINC(CARP_STAT_HDROPS); 550 1.1 liamjfoy return; 551 1.1 liamjfoy } 552 1.1 liamjfoy ip = mtod(m, struct ip *); 553 1.1 liamjfoy ch = (struct carp_header *)((char *)ip + iplen); 554 1.1 liamjfoy /* verify the CARP checksum */ 555 1.1 liamjfoy m->m_data += iplen; 556 1.1 liamjfoy if (carp_cksum(m, len - iplen)) { 557 1.24 thorpej CARP_STATINC(CARP_STAT_BADSUM); 558 1.1 liamjfoy CARP_LOG(sc, ("checksum failed on %s", 559 1.67 ozaki rcvif->if_xname)); 560 1.1 liamjfoy m_freem(m); 561 1.1 liamjfoy return; 562 1.1 liamjfoy } 563 1.1 liamjfoy m->m_data -= iplen; 564 1.1 liamjfoy 565 1.1 liamjfoy carp_proto_input_c(m, ch, AF_INET); 566 1.1 liamjfoy } 567 1.1 liamjfoy 568 1.84 ozaki void 569 1.100 maxv carp_proto_input(struct mbuf *m, int off, int proto) 570 1.84 ozaki { 571 1.84 ozaki 572 1.84 ozaki wqinput_input(carp_wqinput, m, 0, 0); 573 1.84 ozaki } 574 1.84 ozaki 575 1.1 liamjfoy #ifdef INET6 576 1.84 ozaki static void 577 1.84 ozaki _carp6_proto_input(struct mbuf *m, int off, int proto) 578 1.1 liamjfoy { 579 1.1 liamjfoy struct carp_softc *sc = NULL; 580 1.1 liamjfoy struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 581 1.1 liamjfoy struct carp_header *ch; 582 1.1 liamjfoy u_int len; 583 1.67 ozaki struct ifnet *rcvif; 584 1.1 liamjfoy 585 1.24 thorpej CARP_STATINC(CARP_STAT_IPACKETS6); 586 1.53 bouyer MCLAIM(m, &carp_proto6_mowner_rx); 587 1.1 liamjfoy 588 1.1 liamjfoy if (!carp_opts[CARPCTL_ALLOW]) { 589 1.1 liamjfoy m_freem(m); 590 1.84 ozaki return; 591 1.1 liamjfoy } 592 1.1 liamjfoy 593 1.67 ozaki rcvif = m_get_rcvif_NOMPSAFE(m); 594 1.67 ozaki 595 1.1 liamjfoy /* check if received on a valid carp interface */ 596 1.67 ozaki if (rcvif->if_type != IFT_CARP) { 597 1.24 thorpej CARP_STATINC(CARP_STAT_BADIF); 598 1.1 liamjfoy CARP_LOG(sc, ("packet received on non-carp interface: %s", 599 1.67 ozaki rcvif->if_xname)); 600 1.1 liamjfoy m_freem(m); 601 1.84 ozaki return; 602 1.1 liamjfoy } 603 1.1 liamjfoy 604 1.1 liamjfoy /* verify that the IP TTL is 255 */ 605 1.1 liamjfoy if (ip6->ip6_hlim != CARP_DFLTTL) { 606 1.24 thorpej CARP_STATINC(CARP_STAT_BADTTL); 607 1.1 liamjfoy CARP_LOG(sc, ("received ttl %d != %d on %s", ip6->ip6_hlim, 608 1.67 ozaki CARP_DFLTTL, rcvif->if_xname)); 609 1.1 liamjfoy m_freem(m); 610 1.84 ozaki return; 611 1.1 liamjfoy } 612 1.1 liamjfoy 613 1.1 liamjfoy /* verify that we have a complete carp packet */ 614 1.1 liamjfoy len = m->m_len; 615 1.96 maxv M_REGION_GET(ch, struct carp_header *, m, off, sizeof(*ch)); 616 1.1 liamjfoy if (ch == NULL) { 617 1.24 thorpej CARP_STATINC(CARP_STAT_BADLEN); 618 1.1 liamjfoy CARP_LOG(sc, ("packet size %u too small", len)); 619 1.84 ozaki return; 620 1.1 liamjfoy } 621 1.1 liamjfoy 622 1.1 liamjfoy /* verify the CARP checksum */ 623 1.85 ozaki if (carp6_cksum(m, off, sizeof(*ch))) { 624 1.24 thorpej CARP_STATINC(CARP_STAT_BADSUM); 625 1.67 ozaki CARP_LOG(sc, ("checksum failed, on %s", rcvif->if_xname)); 626 1.1 liamjfoy m_freem(m); 627 1.84 ozaki return; 628 1.1 liamjfoy } 629 1.1 liamjfoy 630 1.1 liamjfoy carp_proto_input_c(m, ch, AF_INET6); 631 1.84 ozaki return; 632 1.84 ozaki } 633 1.84 ozaki 634 1.84 ozaki int 635 1.84 ozaki carp6_proto_input(struct mbuf **mp, int *offp, int proto) 636 1.84 ozaki { 637 1.84 ozaki 638 1.84 ozaki wqinput_input(carp6_wqinput, *mp, *offp, proto); 639 1.84 ozaki 640 1.84 ozaki return IPPROTO_DONE; 641 1.1 liamjfoy } 642 1.1 liamjfoy #endif /* INET6 */ 643 1.1 liamjfoy 644 1.58 ozaki static void 645 1.1 liamjfoy carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) 646 1.1 liamjfoy { 647 1.1 liamjfoy struct carp_softc *sc; 648 1.1 liamjfoy u_int64_t tmp_counter; 649 1.1 liamjfoy struct timeval sc_tv, ch_tv; 650 1.1 liamjfoy 651 1.1 liamjfoy TAILQ_FOREACH(sc, &((struct carp_if *) 652 1.67 ozaki m_get_rcvif_NOMPSAFE(m)->if_carpdev->if_carp)->vhif_vrs, sc_list) 653 1.1 liamjfoy if (sc->sc_vhid == ch->carp_vhid) 654 1.1 liamjfoy break; 655 1.1 liamjfoy 656 1.1 liamjfoy if (!sc || (sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != 657 1.1 liamjfoy (IFF_UP|IFF_RUNNING)) { 658 1.24 thorpej CARP_STATINC(CARP_STAT_BADVHID); 659 1.1 liamjfoy m_freem(m); 660 1.1 liamjfoy return; 661 1.1 liamjfoy } 662 1.1 liamjfoy 663 1.2 liamjfoy /* 664 1.2 liamjfoy * Check if our own advertisement was duplicated 665 1.2 liamjfoy * from a non simplex interface. 666 1.2 liamjfoy * XXX If there is no address on our physical interface 667 1.2 liamjfoy * there is no way to distinguish our ads from the ones 668 1.2 liamjfoy * another carp host might have sent us. 669 1.2 liamjfoy */ 670 1.2 liamjfoy if ((sc->sc_carpdev->if_flags & IFF_SIMPLEX) == 0) { 671 1.2 liamjfoy struct sockaddr sa; 672 1.2 liamjfoy struct ifaddr *ifa; 673 1.77 ozaki int s; 674 1.2 liamjfoy 675 1.32 cegger memset(&sa, 0, sizeof(sa)); 676 1.2 liamjfoy sa.sa_family = af; 677 1.77 ozaki s = pserialize_read_enter(); 678 1.2 liamjfoy ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev); 679 1.2 liamjfoy 680 1.2 liamjfoy if (ifa && af == AF_INET) { 681 1.2 liamjfoy struct ip *ip = mtod(m, struct ip *); 682 1.2 liamjfoy if (ip->ip_src.s_addr == 683 1.2 liamjfoy ifatoia(ifa)->ia_addr.sin_addr.s_addr) { 684 1.77 ozaki pserialize_read_exit(s); 685 1.2 liamjfoy m_freem(m); 686 1.2 liamjfoy return; 687 1.2 liamjfoy } 688 1.2 liamjfoy } 689 1.2 liamjfoy #ifdef INET6 690 1.2 liamjfoy if (ifa && af == AF_INET6) { 691 1.2 liamjfoy struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 692 1.2 liamjfoy struct in6_addr in6_src, in6_found; 693 1.2 liamjfoy 694 1.2 liamjfoy in6_src = ip6->ip6_src; 695 1.2 liamjfoy in6_found = ifatoia6(ifa)->ia_addr.sin6_addr; 696 1.2 liamjfoy if (IN6_IS_ADDR_LINKLOCAL(&in6_src)) 697 1.2 liamjfoy in6_src.s6_addr16[1] = 0; 698 1.2 liamjfoy if (IN6_IS_ADDR_LINKLOCAL(&in6_found)) 699 1.2 liamjfoy in6_found.s6_addr16[1] = 0; 700 1.2 liamjfoy if (IN6_ARE_ADDR_EQUAL(&in6_src, &in6_found)) { 701 1.77 ozaki pserialize_read_exit(s); 702 1.2 liamjfoy m_freem(m); 703 1.2 liamjfoy return; 704 1.2 liamjfoy } 705 1.2 liamjfoy } 706 1.2 liamjfoy #endif /* INET6 */ 707 1.77 ozaki pserialize_read_exit(s); 708 1.2 liamjfoy } 709 1.2 liamjfoy 710 1.30 christos nanotime(&sc->sc_if.if_lastchange); 711 1.108 thorpej if_statadd2(&sc->sc_if, if_ipackets, 1, if_ibytes, m->m_pkthdr.len); 712 1.1 liamjfoy 713 1.1 liamjfoy /* verify the CARP version. */ 714 1.1 liamjfoy if (ch->carp_version != CARP_VERSION) { 715 1.24 thorpej CARP_STATINC(CARP_STAT_BADVER); 716 1.108 thorpej if_statinc(&sc->sc_if, if_ierrors); 717 1.1 liamjfoy CARP_LOG(sc, ("invalid version %d != %d", 718 1.1 liamjfoy ch->carp_version, CARP_VERSION)); 719 1.1 liamjfoy m_freem(m); 720 1.1 liamjfoy return; 721 1.1 liamjfoy } 722 1.1 liamjfoy 723 1.1 liamjfoy /* verify the hash */ 724 1.1 liamjfoy if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) { 725 1.76 is struct ip *ip; 726 1.87 ozaki char ipbuf[INET_ADDRSTRLEN]; 727 1.87 ozaki #ifdef INET6 728 1.76 is struct ip6_hdr *ip6; 729 1.82 ryo char ip6buf[INET6_ADDRSTRLEN]; 730 1.87 ozaki #endif 731 1.76 is 732 1.24 thorpej CARP_STATINC(CARP_STAT_BADAUTH); 733 1.108 thorpej if_statinc(&sc->sc_if, if_ierrors); 734 1.76 is 735 1.76 is switch(af) { 736 1.76 is case AF_INET: 737 1.76 is ip = mtod(m, struct ip *); 738 1.76 is CARP_LOG(sc, ("incorrect hash from %s", 739 1.89 ryo IN_PRINT(ipbuf, &ip->ip_src))); 740 1.76 is break; 741 1.76 is 742 1.87 ozaki #ifdef INET6 743 1.76 is case AF_INET6: 744 1.76 is ip6 = mtod(m, struct ip6_hdr *); 745 1.76 is CARP_LOG(sc, ("incorrect hash from %s", 746 1.83 christos IN6_PRINT(ip6buf, &ip6->ip6_src))); 747 1.76 is break; 748 1.87 ozaki #endif 749 1.76 is 750 1.76 is default: CARP_LOG(sc, ("incorrect hash")); 751 1.76 is break; 752 1.76 is } 753 1.1 liamjfoy m_freem(m); 754 1.1 liamjfoy return; 755 1.1 liamjfoy } 756 1.1 liamjfoy 757 1.1 liamjfoy tmp_counter = ntohl(ch->carp_counter[0]); 758 1.1 liamjfoy tmp_counter = tmp_counter<<32; 759 1.1 liamjfoy tmp_counter += ntohl(ch->carp_counter[1]); 760 1.1 liamjfoy 761 1.1 liamjfoy /* XXX Replay protection goes here */ 762 1.1 liamjfoy 763 1.1 liamjfoy sc->sc_init_counter = 0; 764 1.1 liamjfoy sc->sc_counter = tmp_counter; 765 1.1 liamjfoy 766 1.1 liamjfoy 767 1.1 liamjfoy sc_tv.tv_sec = sc->sc_advbase; 768 1.1 liamjfoy if (carp_suppress_preempt && sc->sc_advskew < 240) 769 1.1 liamjfoy sc_tv.tv_usec = 240 * 1000000 / 256; 770 1.1 liamjfoy else 771 1.1 liamjfoy sc_tv.tv_usec = sc->sc_advskew * 1000000 / 256; 772 1.1 liamjfoy ch_tv.tv_sec = ch->carp_advbase; 773 1.1 liamjfoy ch_tv.tv_usec = ch->carp_advskew * 1000000 / 256; 774 1.1 liamjfoy 775 1.1 liamjfoy switch (sc->sc_state) { 776 1.1 liamjfoy case INIT: 777 1.1 liamjfoy break; 778 1.1 liamjfoy case MASTER: 779 1.1 liamjfoy /* 780 1.1 liamjfoy * If we receive an advertisement from a backup who's going to 781 1.1 liamjfoy * be more frequent than us, go into BACKUP state. 782 1.1 liamjfoy */ 783 1.1 liamjfoy if (timercmp(&sc_tv, &ch_tv, >) || 784 1.1 liamjfoy timercmp(&sc_tv, &ch_tv, ==)) { 785 1.1 liamjfoy callout_stop(&sc->sc_ad_tmo); 786 1.38 taca CARP_LOG(sc, ("MASTER -> BACKUP (more frequent advertisement received)")); 787 1.1 liamjfoy carp_set_state(sc, BACKUP); 788 1.1 liamjfoy carp_setrun(sc, 0); 789 1.1 liamjfoy carp_setroute(sc, RTM_DELETE); 790 1.1 liamjfoy } 791 1.1 liamjfoy break; 792 1.1 liamjfoy case BACKUP: 793 1.1 liamjfoy /* 794 1.1 liamjfoy * If we're pre-empting masters who advertise slower than us, 795 1.1 liamjfoy * and this one claims to be slower, treat him as down. 796 1.1 liamjfoy */ 797 1.1 liamjfoy if (carp_opts[CARPCTL_PREEMPT] && timercmp(&sc_tv, &ch_tv, <)) { 798 1.38 taca CARP_LOG(sc, ("BACKUP -> MASTER (preempting a slower master)")); 799 1.1 liamjfoy carp_master_down(sc); 800 1.1 liamjfoy break; 801 1.1 liamjfoy } 802 1.1 liamjfoy 803 1.1 liamjfoy /* 804 1.1 liamjfoy * If the master is going to advertise at such a low frequency 805 1.1 liamjfoy * that he's guaranteed to time out, we'd might as well just 806 1.1 liamjfoy * treat him as timed out now. 807 1.1 liamjfoy */ 808 1.1 liamjfoy sc_tv.tv_sec = sc->sc_advbase * 3; 809 1.1 liamjfoy if (timercmp(&sc_tv, &ch_tv, <)) { 810 1.38 taca CARP_LOG(sc, ("BACKUP -> MASTER (master timed out)")); 811 1.1 liamjfoy carp_master_down(sc); 812 1.1 liamjfoy break; 813 1.1 liamjfoy } 814 1.1 liamjfoy 815 1.1 liamjfoy /* 816 1.1 liamjfoy * Otherwise, we reset the counter and wait for the next 817 1.1 liamjfoy * advertisement. 818 1.1 liamjfoy */ 819 1.1 liamjfoy carp_setrun(sc, af); 820 1.1 liamjfoy break; 821 1.1 liamjfoy } 822 1.1 liamjfoy 823 1.1 liamjfoy m_freem(m); 824 1.1 liamjfoy return; 825 1.1 liamjfoy } 826 1.1 liamjfoy 827 1.1 liamjfoy /* 828 1.1 liamjfoy * Interface side of the CARP implementation. 829 1.1 liamjfoy */ 830 1.1 liamjfoy 831 1.1 liamjfoy /* ARGSUSED */ 832 1.1 liamjfoy void 833 1.10 christos carpattach(int n) 834 1.1 liamjfoy { 835 1.1 liamjfoy if_clone_attach(&carp_cloner); 836 1.24 thorpej 837 1.24 thorpej carpstat_percpu = percpu_alloc(sizeof(uint64_t) * CARP_NSTATS); 838 1.1 liamjfoy } 839 1.1 liamjfoy 840 1.58 ozaki static int 841 1.1 liamjfoy carp_clone_create(struct if_clone *ifc, int unit) 842 1.1 liamjfoy { 843 1.1 liamjfoy extern int ifqmaxlen; 844 1.1 liamjfoy struct carp_softc *sc; 845 1.1 liamjfoy struct ifnet *ifp; 846 1.1 liamjfoy 847 1.29 cegger sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO); 848 1.1 liamjfoy if (!sc) 849 1.1 liamjfoy return (ENOMEM); 850 1.1 liamjfoy 851 1.1 liamjfoy sc->sc_suppress = 0; 852 1.1 liamjfoy sc->sc_advbase = CARP_DFLTINTV; 853 1.1 liamjfoy sc->sc_vhid = -1; /* required setting */ 854 1.1 liamjfoy sc->sc_advskew = 0; 855 1.1 liamjfoy sc->sc_init_counter = 1; 856 1.1 liamjfoy sc->sc_naddrs = sc->sc_naddrs6 = 0; 857 1.1 liamjfoy #ifdef INET6 858 1.1 liamjfoy sc->sc_im6o.im6o_multicast_hlim = CARP_DFLTTL; 859 1.1 liamjfoy #endif /* INET6 */ 860 1.1 liamjfoy 861 1.13 ad callout_init(&sc->sc_ad_tmo, 0); 862 1.13 ad callout_init(&sc->sc_md_tmo, 0); 863 1.13 ad callout_init(&sc->sc_md6_tmo, 0); 864 1.1 liamjfoy 865 1.1 liamjfoy callout_setfunc(&sc->sc_ad_tmo, carp_send_ad, sc); 866 1.1 liamjfoy callout_setfunc(&sc->sc_md_tmo, carp_master_down, sc); 867 1.1 liamjfoy callout_setfunc(&sc->sc_md6_tmo, carp_master_down, sc); 868 1.1 liamjfoy 869 1.1 liamjfoy LIST_INIT(&sc->carp_mc_listhead); 870 1.1 liamjfoy ifp = &sc->sc_if; 871 1.1 liamjfoy ifp->if_softc = sc; 872 1.1 liamjfoy snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name, 873 1.1 liamjfoy unit); 874 1.1 liamjfoy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 875 1.1 liamjfoy ifp->if_ioctl = carp_ioctl; 876 1.1 liamjfoy ifp->if_start = carp_start; 877 1.1 liamjfoy IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 878 1.1 liamjfoy IFQ_SET_READY(&ifp->if_snd); 879 1.115 riastrad if_initialize(ifp); 880 1.81 ozaki ether_ifattach(ifp, NULL); 881 1.81 ozaki /* Overwrite ethernet defaults */ 882 1.81 ozaki ifp->if_type = IFT_CARP; 883 1.81 ozaki ifp->if_output = carp_output; 884 1.113 roy ifp->if_link_state = LINK_STATE_DOWN; 885 1.112 roy carp_set_enaddr(sc); 886 1.81 ozaki if_register(ifp); 887 1.1 liamjfoy 888 1.1 liamjfoy return (0); 889 1.1 liamjfoy } 890 1.1 liamjfoy 891 1.58 ozaki static int 892 1.1 liamjfoy carp_clone_destroy(struct ifnet *ifp) 893 1.1 liamjfoy { 894 1.13 ad struct carp_softc *sc = ifp->if_softc; 895 1.13 ad 896 1.1 liamjfoy carpdetach(ifp->if_softc); 897 1.1 liamjfoy ether_ifdetach(ifp); 898 1.1 liamjfoy if_detach(ifp); 899 1.13 ad callout_destroy(&sc->sc_ad_tmo); 900 1.13 ad callout_destroy(&sc->sc_md_tmo); 901 1.13 ad callout_destroy(&sc->sc_md6_tmo); 902 1.1 liamjfoy free(ifp->if_softc, M_DEVBUF); 903 1.1 liamjfoy 904 1.1 liamjfoy return (0); 905 1.1 liamjfoy } 906 1.1 liamjfoy 907 1.58 ozaki static void 908 1.1 liamjfoy carpdetach(struct carp_softc *sc) 909 1.1 liamjfoy { 910 1.116 yamaguch struct ifnet *ifp; 911 1.1 liamjfoy struct carp_if *cif; 912 1.1 liamjfoy int s; 913 1.1 liamjfoy 914 1.1 liamjfoy callout_stop(&sc->sc_ad_tmo); 915 1.1 liamjfoy callout_stop(&sc->sc_md_tmo); 916 1.1 liamjfoy callout_stop(&sc->sc_md6_tmo); 917 1.1 liamjfoy 918 1.1 liamjfoy if (sc->sc_suppress) 919 1.1 liamjfoy carp_suppress_preempt--; 920 1.1 liamjfoy sc->sc_suppress = 0; 921 1.1 liamjfoy 922 1.1 liamjfoy if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) 923 1.1 liamjfoy carp_suppress_preempt--; 924 1.1 liamjfoy sc->sc_sendad_errors = 0; 925 1.1 liamjfoy 926 1.1 liamjfoy carp_set_state(sc, INIT); 927 1.1 liamjfoy sc->sc_if.if_flags &= ~IFF_UP; 928 1.1 liamjfoy carp_setrun(sc, 0); 929 1.1 liamjfoy carp_multicast_cleanup(sc); 930 1.1 liamjfoy 931 1.54 bouyer KERNEL_LOCK(1, NULL); 932 1.1 liamjfoy s = splnet(); 933 1.116 yamaguch ifp = sc->sc_carpdev; 934 1.116 yamaguch if (ifp != NULL) { 935 1.116 yamaguch if_linkstate_change_disestablish(ifp, 936 1.116 yamaguch sc->sc_linkstate_hook, NULL); 937 1.116 yamaguch 938 1.116 yamaguch cif = (struct carp_if *)ifp->if_carp; 939 1.1 liamjfoy TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list); 940 1.1 liamjfoy if (!--cif->vhif_nvrs) { 941 1.116 yamaguch ifpromisc(ifp, 0); 942 1.116 yamaguch ifp->if_carp = NULL; 943 1.28 cegger free(cif, M_IFADDR); 944 1.1 liamjfoy } 945 1.1 liamjfoy } 946 1.1 liamjfoy sc->sc_carpdev = NULL; 947 1.1 liamjfoy splx(s); 948 1.54 bouyer KERNEL_UNLOCK_ONE(NULL); 949 1.1 liamjfoy } 950 1.1 liamjfoy 951 1.1 liamjfoy /* Detach an interface from the carp. */ 952 1.1 liamjfoy void 953 1.1 liamjfoy carp_ifdetach(struct ifnet *ifp) 954 1.1 liamjfoy { 955 1.1 liamjfoy struct carp_softc *sc, *nextsc; 956 1.1 liamjfoy struct carp_if *cif = (struct carp_if *)ifp->if_carp; 957 1.1 liamjfoy 958 1.1 liamjfoy for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) { 959 1.1 liamjfoy nextsc = TAILQ_NEXT(sc, sc_list); 960 1.1 liamjfoy carpdetach(sc); 961 1.1 liamjfoy } 962 1.1 liamjfoy } 963 1.1 liamjfoy 964 1.95 maxv static void 965 1.10 christos carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, 966 1.6 christos struct carp_header *ch) 967 1.1 liamjfoy { 968 1.1 liamjfoy if (sc->sc_init_counter) { 969 1.1 liamjfoy /* this could also be seconds since unix epoch */ 970 1.47 tls sc->sc_counter = cprng_fast64(); 971 1.1 liamjfoy } else 972 1.1 liamjfoy sc->sc_counter++; 973 1.1 liamjfoy 974 1.1 liamjfoy ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff); 975 1.1 liamjfoy ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff); 976 1.1 liamjfoy 977 1.1 liamjfoy carp_hmac_generate(sc, ch->carp_counter, ch->carp_md); 978 1.1 liamjfoy } 979 1.1 liamjfoy 980 1.58 ozaki static void 981 1.1 liamjfoy carp_send_ad_all(void) 982 1.1 liamjfoy { 983 1.1 liamjfoy struct ifnet *ifp; 984 1.1 liamjfoy struct carp_if *cif; 985 1.1 liamjfoy struct carp_softc *vh; 986 1.65 ozaki int s; 987 1.68 ozaki int bound = curlwp_bind(); 988 1.1 liamjfoy 989 1.65 ozaki s = pserialize_read_enter(); 990 1.65 ozaki IFNET_READER_FOREACH(ifp) { 991 1.65 ozaki struct psref psref; 992 1.1 liamjfoy if (ifp->if_carp == NULL || ifp->if_type == IFT_CARP) 993 1.1 liamjfoy continue; 994 1.1 liamjfoy 995 1.86 ozaki if_acquire(ifp, &psref); 996 1.65 ozaki pserialize_read_exit(s); 997 1.65 ozaki 998 1.1 liamjfoy cif = (struct carp_if *)ifp->if_carp; 999 1.1 liamjfoy TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1000 1.1 liamjfoy if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == 1001 1.1 liamjfoy (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER) 1002 1.1 liamjfoy carp_send_ad(vh); 1003 1.1 liamjfoy } 1004 1.65 ozaki 1005 1.65 ozaki s = pserialize_read_enter(); 1006 1.86 ozaki if_release(ifp, &psref); 1007 1.1 liamjfoy } 1008 1.65 ozaki pserialize_read_exit(s); 1009 1.68 ozaki curlwp_bindx(bound); 1010 1.1 liamjfoy } 1011 1.1 liamjfoy 1012 1.1 liamjfoy 1013 1.58 ozaki static void 1014 1.1 liamjfoy carp_send_ad(void *v) 1015 1.1 liamjfoy { 1016 1.1 liamjfoy struct carp_header ch; 1017 1.1 liamjfoy struct timeval tv; 1018 1.1 liamjfoy struct carp_softc *sc = v; 1019 1.1 liamjfoy struct carp_header *ch_ptr; 1020 1.1 liamjfoy struct mbuf *m; 1021 1.1 liamjfoy int error, len, advbase, advskew, s; 1022 1.1 liamjfoy struct sockaddr sa; 1023 1.1 liamjfoy 1024 1.54 bouyer KERNEL_LOCK(1, NULL); 1025 1.1 liamjfoy s = splsoftnet(); 1026 1.1 liamjfoy 1027 1.1 liamjfoy advbase = advskew = 0; /* Sssssh compiler */ 1028 1.1 liamjfoy if (sc->sc_carpdev == NULL) { 1029 1.108 thorpej if_statinc(&sc->sc_if, if_oerrors); 1030 1.1 liamjfoy goto retry_later; 1031 1.1 liamjfoy } 1032 1.1 liamjfoy 1033 1.1 liamjfoy /* bow out if we've gone to backup (the carp interface is going down) */ 1034 1.1 liamjfoy if (sc->sc_bow_out) { 1035 1.1 liamjfoy sc->sc_bow_out = 0; 1036 1.1 liamjfoy advbase = 255; 1037 1.1 liamjfoy advskew = 255; 1038 1.1 liamjfoy } else { 1039 1.1 liamjfoy advbase = sc->sc_advbase; 1040 1.1 liamjfoy if (!carp_suppress_preempt || sc->sc_advskew > 240) 1041 1.1 liamjfoy advskew = sc->sc_advskew; 1042 1.1 liamjfoy else 1043 1.1 liamjfoy advskew = 240; 1044 1.1 liamjfoy tv.tv_sec = advbase; 1045 1.1 liamjfoy tv.tv_usec = advskew * 1000000 / 256; 1046 1.1 liamjfoy } 1047 1.1 liamjfoy 1048 1.1 liamjfoy ch.carp_version = CARP_VERSION; 1049 1.1 liamjfoy ch.carp_type = CARP_ADVERTISEMENT; 1050 1.1 liamjfoy ch.carp_vhid = sc->sc_vhid; 1051 1.1 liamjfoy ch.carp_advbase = advbase; 1052 1.1 liamjfoy ch.carp_advskew = advskew; 1053 1.1 liamjfoy ch.carp_authlen = 7; /* XXX DEFINE */ 1054 1.1 liamjfoy ch.carp_pad1 = 0; /* must be zero */ 1055 1.1 liamjfoy ch.carp_cksum = 0; 1056 1.1 liamjfoy 1057 1.1 liamjfoy 1058 1.1 liamjfoy #ifdef INET 1059 1.1 liamjfoy if (sc->sc_naddrs) { 1060 1.1 liamjfoy struct ip *ip; 1061 1.77 ozaki struct ifaddr *ifa; 1062 1.77 ozaki int _s; 1063 1.1 liamjfoy 1064 1.1 liamjfoy MGETHDR(m, M_DONTWAIT, MT_HEADER); 1065 1.1 liamjfoy if (m == NULL) { 1066 1.108 thorpej if_statinc(&sc->sc_if, if_oerrors); 1067 1.24 thorpej CARP_STATINC(CARP_STAT_ONOMEM); 1068 1.1 liamjfoy /* XXX maybe less ? */ 1069 1.1 liamjfoy goto retry_later; 1070 1.1 liamjfoy } 1071 1.53 bouyer MCLAIM(m, &carp_proto_mowner_tx); 1072 1.1 liamjfoy len = sizeof(*ip) + sizeof(ch); 1073 1.1 liamjfoy m->m_pkthdr.len = len; 1074 1.66 ozaki m_reset_rcvif(m); 1075 1.1 liamjfoy m->m_len = len; 1076 1.101 maxv m_align(m, m->m_len); 1077 1.1 liamjfoy m->m_flags |= M_MCAST; 1078 1.1 liamjfoy ip = mtod(m, struct ip *); 1079 1.1 liamjfoy ip->ip_v = IPVERSION; 1080 1.1 liamjfoy ip->ip_hl = sizeof(*ip) >> 2; 1081 1.1 liamjfoy ip->ip_tos = IPTOS_LOWDELAY; 1082 1.1 liamjfoy ip->ip_len = htons(len); 1083 1.22 matt ip->ip_id = 0; /* no need for id, we don't support fragments */ 1084 1.1 liamjfoy ip->ip_off = htons(IP_DF); 1085 1.1 liamjfoy ip->ip_ttl = CARP_DFLTTL; 1086 1.1 liamjfoy ip->ip_p = IPPROTO_CARP; 1087 1.1 liamjfoy ip->ip_sum = 0; 1088 1.1 liamjfoy 1089 1.32 cegger memset(&sa, 0, sizeof(sa)); 1090 1.1 liamjfoy sa.sa_family = AF_INET; 1091 1.77 ozaki _s = pserialize_read_enter(); 1092 1.1 liamjfoy ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev); 1093 1.1 liamjfoy if (ifa == NULL) 1094 1.119 mlelstv ifa = ifaof_ifpforaddr(&sa, &sc->sc_if); 1095 1.119 mlelstv if (ifa == NULL) 1096 1.1 liamjfoy ip->ip_src.s_addr = 0; 1097 1.1 liamjfoy else 1098 1.1 liamjfoy ip->ip_src.s_addr = 1099 1.1 liamjfoy ifatoia(ifa)->ia_addr.sin_addr.s_addr; 1100 1.77 ozaki pserialize_read_exit(_s); 1101 1.1 liamjfoy ip->ip_dst.s_addr = INADDR_CARP_GROUP; 1102 1.1 liamjfoy 1103 1.1 liamjfoy ch_ptr = (struct carp_header *)(&ip[1]); 1104 1.34 tsutsui memcpy(ch_ptr, &ch, sizeof(ch)); 1105 1.95 maxv carp_prepare_ad(m, sc, ch_ptr); 1106 1.1 liamjfoy 1107 1.1 liamjfoy m->m_data += sizeof(*ip); 1108 1.1 liamjfoy ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip)); 1109 1.1 liamjfoy m->m_data -= sizeof(*ip); 1110 1.1 liamjfoy 1111 1.30 christos nanotime(&sc->sc_if.if_lastchange); 1112 1.108 thorpej if_statadd2(&sc->sc_if, if_opackets, 1, if_obytes, len); 1113 1.24 thorpej CARP_STATINC(CARP_STAT_OPACKETS); 1114 1.1 liamjfoy 1115 1.1 liamjfoy error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, 1116 1.1 liamjfoy NULL); 1117 1.1 liamjfoy if (error) { 1118 1.1 liamjfoy if (error == ENOBUFS) 1119 1.24 thorpej CARP_STATINC(CARP_STAT_ONOMEM); 1120 1.1 liamjfoy else 1121 1.1 liamjfoy CARP_LOG(sc, ("ip_output failed: %d", error)); 1122 1.108 thorpej if_statinc(&sc->sc_if, if_oerrors); 1123 1.1 liamjfoy if (sc->sc_sendad_errors < INT_MAX) 1124 1.1 liamjfoy sc->sc_sendad_errors++; 1125 1.1 liamjfoy if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) { 1126 1.1 liamjfoy carp_suppress_preempt++; 1127 1.1 liamjfoy if (carp_suppress_preempt == 1) 1128 1.1 liamjfoy carp_send_ad_all(); 1129 1.1 liamjfoy } 1130 1.1 liamjfoy sc->sc_sendad_success = 0; 1131 1.1 liamjfoy } else { 1132 1.1 liamjfoy if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) { 1133 1.1 liamjfoy if (++sc->sc_sendad_success >= 1134 1.1 liamjfoy CARP_SENDAD_MIN_SUCCESS) { 1135 1.1 liamjfoy carp_suppress_preempt--; 1136 1.1 liamjfoy sc->sc_sendad_errors = 0; 1137 1.1 liamjfoy } 1138 1.1 liamjfoy } else 1139 1.1 liamjfoy sc->sc_sendad_errors = 0; 1140 1.1 liamjfoy } 1141 1.1 liamjfoy } 1142 1.1 liamjfoy #endif /* INET */ 1143 1.85 ozaki #ifdef INET6 1144 1.1 liamjfoy if (sc->sc_naddrs6) { 1145 1.1 liamjfoy struct ip6_hdr *ip6; 1146 1.77 ozaki struct ifaddr *ifa; 1147 1.119 mlelstv struct ifnet *ifp; 1148 1.77 ozaki int _s; 1149 1.1 liamjfoy 1150 1.1 liamjfoy MGETHDR(m, M_DONTWAIT, MT_HEADER); 1151 1.1 liamjfoy if (m == NULL) { 1152 1.108 thorpej if_statinc(&sc->sc_if, if_oerrors); 1153 1.24 thorpej CARP_STATINC(CARP_STAT_ONOMEM); 1154 1.1 liamjfoy /* XXX maybe less ? */ 1155 1.1 liamjfoy goto retry_later; 1156 1.1 liamjfoy } 1157 1.53 bouyer MCLAIM(m, &carp_proto6_mowner_tx); 1158 1.1 liamjfoy len = sizeof(*ip6) + sizeof(ch); 1159 1.1 liamjfoy m->m_pkthdr.len = len; 1160 1.66 ozaki m_reset_rcvif(m); 1161 1.1 liamjfoy m->m_len = len; 1162 1.101 maxv m_align(m, m->m_len); 1163 1.1 liamjfoy m->m_flags |= M_MCAST; 1164 1.1 liamjfoy ip6 = mtod(m, struct ip6_hdr *); 1165 1.32 cegger memset(ip6, 0, sizeof(*ip6)); 1166 1.1 liamjfoy ip6->ip6_vfc |= IPV6_VERSION; 1167 1.1 liamjfoy ip6->ip6_hlim = CARP_DFLTTL; 1168 1.1 liamjfoy ip6->ip6_nxt = IPPROTO_CARP; 1169 1.1 liamjfoy 1170 1.1 liamjfoy /* set the source address */ 1171 1.32 cegger memset(&sa, 0, sizeof(sa)); 1172 1.1 liamjfoy sa.sa_family = AF_INET6; 1173 1.77 ozaki _s = pserialize_read_enter(); 1174 1.119 mlelstv ifp = sc->sc_carpdev; 1175 1.119 mlelstv ifa = ifaof_ifpforaddr(&sa, ifp); 1176 1.119 mlelstv if (ifa == NULL) { /* This should never happen with IPv6 */ 1177 1.119 mlelstv ifp = &sc->sc_if; 1178 1.119 mlelstv ifa = ifaof_ifpforaddr(&sa, ifp); 1179 1.119 mlelstv } 1180 1.1 liamjfoy if (ifa == NULL) /* This should never happen with IPv6 */ 1181 1.32 cegger memset(&ip6->ip6_src, 0, sizeof(struct in6_addr)); 1182 1.1 liamjfoy else 1183 1.1 liamjfoy bcopy(ifatoia6(ifa)->ia_addr.sin6_addr.s6_addr, 1184 1.1 liamjfoy &ip6->ip6_src, sizeof(struct in6_addr)); 1185 1.77 ozaki pserialize_read_exit(_s); 1186 1.1 liamjfoy /* set the multicast destination */ 1187 1.1 liamjfoy 1188 1.23 ws ip6->ip6_dst.s6_addr16[0] = htons(0xff02); 1189 1.1 liamjfoy ip6->ip6_dst.s6_addr8[15] = 0x12; 1190 1.119 mlelstv if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) { 1191 1.108 thorpej if_statinc(&sc->sc_if, if_oerrors); 1192 1.23 ws m_freem(m); 1193 1.23 ws CARP_LOG(sc, ("in6_setscope failed")); 1194 1.23 ws goto retry_later; 1195 1.23 ws } 1196 1.1 liamjfoy 1197 1.1 liamjfoy ch_ptr = (struct carp_header *)(&ip6[1]); 1198 1.34 tsutsui memcpy(ch_ptr, &ch, sizeof(ch)); 1199 1.95 maxv carp_prepare_ad(m, sc, ch_ptr); 1200 1.1 liamjfoy 1201 1.85 ozaki ch_ptr->carp_cksum = carp6_cksum(m, sizeof(*ip6), 1202 1.85 ozaki len - sizeof(*ip6)); 1203 1.1 liamjfoy 1204 1.30 christos nanotime(&sc->sc_if.if_lastchange); 1205 1.108 thorpej if_statadd2(&sc->sc_if, if_opackets, 1, if_obytes, len); 1206 1.24 thorpej CARP_STATINC(CARP_STAT_OPACKETS6); 1207 1.1 liamjfoy 1208 1.1 liamjfoy error = ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL); 1209 1.1 liamjfoy if (error) { 1210 1.1 liamjfoy if (error == ENOBUFS) 1211 1.24 thorpej CARP_STATINC(CARP_STAT_ONOMEM); 1212 1.1 liamjfoy else 1213 1.1 liamjfoy CARP_LOG(sc, ("ip6_output failed: %d", error)); 1214 1.108 thorpej if_statinc(&sc->sc_if, if_oerrors); 1215 1.1 liamjfoy if (sc->sc_sendad_errors < INT_MAX) 1216 1.1 liamjfoy sc->sc_sendad_errors++; 1217 1.1 liamjfoy if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) { 1218 1.1 liamjfoy carp_suppress_preempt++; 1219 1.1 liamjfoy if (carp_suppress_preempt == 1) 1220 1.1 liamjfoy carp_send_ad_all(); 1221 1.1 liamjfoy } 1222 1.1 liamjfoy sc->sc_sendad_success = 0; 1223 1.1 liamjfoy } else { 1224 1.1 liamjfoy if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) { 1225 1.1 liamjfoy if (++sc->sc_sendad_success >= 1226 1.1 liamjfoy CARP_SENDAD_MIN_SUCCESS) { 1227 1.1 liamjfoy carp_suppress_preempt--; 1228 1.1 liamjfoy sc->sc_sendad_errors = 0; 1229 1.1 liamjfoy } 1230 1.1 liamjfoy } else 1231 1.1 liamjfoy sc->sc_sendad_errors = 0; 1232 1.1 liamjfoy } 1233 1.1 liamjfoy } 1234 1.1 liamjfoy #endif /* INET6 */ 1235 1.1 liamjfoy 1236 1.1 liamjfoy retry_later: 1237 1.1 liamjfoy splx(s); 1238 1.54 bouyer KERNEL_UNLOCK_ONE(NULL); 1239 1.1 liamjfoy if (advbase != 255 || advskew != 255) 1240 1.1 liamjfoy callout_schedule(&sc->sc_ad_tmo, tvtohz(&tv)); 1241 1.1 liamjfoy } 1242 1.1 liamjfoy 1243 1.1 liamjfoy /* 1244 1.1 liamjfoy * Broadcast a gratuitous ARP request containing 1245 1.1 liamjfoy * the virtual router MAC address for each IP address 1246 1.1 liamjfoy * associated with the virtual router. 1247 1.1 liamjfoy */ 1248 1.58 ozaki static void 1249 1.1 liamjfoy carp_send_arp(struct carp_softc *sc) 1250 1.1 liamjfoy { 1251 1.1 liamjfoy struct ifaddr *ifa; 1252 1.93 ozaki int s, bound; 1253 1.1 liamjfoy 1254 1.54 bouyer KERNEL_LOCK(1, NULL); 1255 1.93 ozaki bound = curlwp_bind(); 1256 1.93 ozaki s = pserialize_read_enter(); 1257 1.74 ozaki IFADDR_READER_FOREACH(ifa, &sc->sc_if) { 1258 1.93 ozaki struct psref psref; 1259 1.1 liamjfoy 1260 1.1 liamjfoy if (ifa->ifa_addr->sa_family != AF_INET) 1261 1.1 liamjfoy continue; 1262 1.1 liamjfoy 1263 1.93 ozaki ifa_acquire(ifa, &psref); 1264 1.93 ozaki pserialize_read_exit(s); 1265 1.93 ozaki 1266 1.78 roy arpannounce(sc->sc_carpdev, ifa, CLLADDR(sc->sc_if.if_sadl)); 1267 1.93 ozaki 1268 1.93 ozaki s = pserialize_read_enter(); 1269 1.93 ozaki ifa_release(ifa, &psref); 1270 1.1 liamjfoy } 1271 1.93 ozaki pserialize_read_exit(s); 1272 1.93 ozaki curlwp_bindx(bound); 1273 1.54 bouyer KERNEL_UNLOCK_ONE(NULL); 1274 1.1 liamjfoy } 1275 1.1 liamjfoy 1276 1.1 liamjfoy #ifdef INET6 1277 1.58 ozaki static void 1278 1.1 liamjfoy carp_send_na(struct carp_softc *sc) 1279 1.1 liamjfoy { 1280 1.1 liamjfoy struct ifaddr *ifa; 1281 1.1 liamjfoy struct in6_addr *in6; 1282 1.1 liamjfoy static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; 1283 1.93 ozaki int s, bound; 1284 1.54 bouyer 1285 1.54 bouyer KERNEL_LOCK(1, NULL); 1286 1.93 ozaki bound = curlwp_bind(); 1287 1.93 ozaki s = pserialize_read_enter(); 1288 1.74 ozaki IFADDR_READER_FOREACH(ifa, &sc->sc_if) { 1289 1.93 ozaki struct psref psref; 1290 1.1 liamjfoy 1291 1.1 liamjfoy if (ifa->ifa_addr->sa_family != AF_INET6) 1292 1.1 liamjfoy continue; 1293 1.1 liamjfoy 1294 1.93 ozaki ifa_acquire(ifa, &psref); 1295 1.93 ozaki pserialize_read_exit(s); 1296 1.93 ozaki 1297 1.1 liamjfoy in6 = &ifatoia6(ifa)->ia_addr.sin6_addr; 1298 1.1 liamjfoy nd6_na_output(sc->sc_carpdev, &mcast, in6, 1299 1.1 liamjfoy ND_NA_FLAG_OVERRIDE, 1, NULL); 1300 1.93 ozaki 1301 1.93 ozaki s = pserialize_read_enter(); 1302 1.93 ozaki ifa_release(ifa, &psref); 1303 1.1 liamjfoy } 1304 1.93 ozaki pserialize_read_exit(s); 1305 1.93 ozaki curlwp_bindx(bound); 1306 1.54 bouyer KERNEL_UNLOCK_ONE(NULL); 1307 1.1 liamjfoy } 1308 1.1 liamjfoy #endif /* INET6 */ 1309 1.1 liamjfoy 1310 1.1 liamjfoy /* 1311 1.1 liamjfoy * Based on bridge_hash() in if_bridge.c 1312 1.1 liamjfoy */ 1313 1.1 liamjfoy #define mix(a,b,c) \ 1314 1.1 liamjfoy do { \ 1315 1.1 liamjfoy a -= b; a -= c; a ^= (c >> 13); \ 1316 1.1 liamjfoy b -= c; b -= a; b ^= (a << 8); \ 1317 1.1 liamjfoy c -= a; c -= b; c ^= (b >> 13); \ 1318 1.1 liamjfoy a -= b; a -= c; a ^= (c >> 12); \ 1319 1.1 liamjfoy b -= c; b -= a; b ^= (a << 16); \ 1320 1.1 liamjfoy c -= a; c -= b; c ^= (b >> 5); \ 1321 1.1 liamjfoy a -= b; a -= c; a ^= (c >> 3); \ 1322 1.1 liamjfoy b -= c; b -= a; b ^= (a << 10); \ 1323 1.1 liamjfoy c -= a; c -= b; c ^= (b >> 15); \ 1324 1.1 liamjfoy } while (0) 1325 1.1 liamjfoy 1326 1.58 ozaki static u_int32_t 1327 1.1 liamjfoy carp_hash(struct carp_softc *sc, u_char *src) 1328 1.1 liamjfoy { 1329 1.1 liamjfoy u_int32_t a = 0x9e3779b9, b = sc->sc_hashkey[0], c = sc->sc_hashkey[1]; 1330 1.1 liamjfoy 1331 1.1 liamjfoy c += sc->sc_key[3] << 24; 1332 1.1 liamjfoy c += sc->sc_key[2] << 16; 1333 1.1 liamjfoy c += sc->sc_key[1] << 8; 1334 1.1 liamjfoy c += sc->sc_key[0]; 1335 1.1 liamjfoy b += src[5] << 8; 1336 1.1 liamjfoy b += src[4]; 1337 1.1 liamjfoy a += src[3] << 24; 1338 1.1 liamjfoy a += src[2] << 16; 1339 1.1 liamjfoy a += src[1] << 8; 1340 1.1 liamjfoy a += src[0]; 1341 1.1 liamjfoy 1342 1.1 liamjfoy mix(a, b, c); 1343 1.1 liamjfoy return (c); 1344 1.1 liamjfoy } 1345 1.1 liamjfoy 1346 1.58 ozaki static int 1347 1.1 liamjfoy carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type) 1348 1.1 liamjfoy { 1349 1.1 liamjfoy struct carp_softc *vh; 1350 1.1 liamjfoy struct ifaddr *ifa; 1351 1.1 liamjfoy int count = 0; 1352 1.1 liamjfoy 1353 1.1 liamjfoy TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1354 1.1 liamjfoy if ((type == CARP_COUNT_RUNNING && 1355 1.1 liamjfoy (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == 1356 1.1 liamjfoy (IFF_UP|IFF_RUNNING)) || 1357 1.1 liamjfoy (type == CARP_COUNT_MASTER && vh->sc_state == MASTER)) { 1358 1.93 ozaki int s = pserialize_read_enter(); 1359 1.74 ozaki IFADDR_READER_FOREACH(ifa, &vh->sc_if) { 1360 1.1 liamjfoy if (ifa->ifa_addr->sa_family == AF_INET && 1361 1.1 liamjfoy ia->ia_addr.sin_addr.s_addr == 1362 1.1 liamjfoy ifatoia(ifa)->ia_addr.sin_addr.s_addr) 1363 1.1 liamjfoy count++; 1364 1.1 liamjfoy } 1365 1.93 ozaki pserialize_read_exit(s); 1366 1.1 liamjfoy } 1367 1.1 liamjfoy } 1368 1.1 liamjfoy return (count); 1369 1.1 liamjfoy } 1370 1.1 liamjfoy 1371 1.1 liamjfoy int 1372 1.1 liamjfoy carp_iamatch(struct in_ifaddr *ia, u_char *src, 1373 1.1 liamjfoy u_int32_t *count, u_int32_t index) 1374 1.1 liamjfoy { 1375 1.1 liamjfoy struct carp_softc *sc = ia->ia_ifp->if_softc; 1376 1.1 liamjfoy 1377 1.1 liamjfoy if (carp_opts[CARPCTL_ARPBALANCE]) { 1378 1.1 liamjfoy /* 1379 1.1 liamjfoy * We use the source ip to decide which virtual host should 1380 1.1 liamjfoy * handle the request. If we're master of that virtual host, 1381 1.1 liamjfoy * then we respond, otherwise, just drop the arp packet on 1382 1.1 liamjfoy * the floor. 1383 1.1 liamjfoy */ 1384 1.1 liamjfoy 1385 1.1 liamjfoy /* Count the elegible carp interfaces with this address */ 1386 1.1 liamjfoy if (*count == 0) 1387 1.1 liamjfoy *count = carp_addrcount( 1388 1.1 liamjfoy (struct carp_if *)ia->ia_ifp->if_carpdev->if_carp, 1389 1.1 liamjfoy ia, CARP_COUNT_RUNNING); 1390 1.1 liamjfoy 1391 1.1 liamjfoy /* This should never happen, but... */ 1392 1.1 liamjfoy if (*count == 0) 1393 1.1 liamjfoy return (0); 1394 1.1 liamjfoy 1395 1.1 liamjfoy if (carp_hash(sc, src) % *count == index - 1 && 1396 1.1 liamjfoy sc->sc_state == MASTER) { 1397 1.1 liamjfoy return (1); 1398 1.1 liamjfoy } 1399 1.1 liamjfoy } else { 1400 1.1 liamjfoy if (sc->sc_state == MASTER) 1401 1.1 liamjfoy return (1); 1402 1.1 liamjfoy } 1403 1.1 liamjfoy 1404 1.1 liamjfoy return (0); 1405 1.1 liamjfoy } 1406 1.1 liamjfoy 1407 1.1 liamjfoy #ifdef INET6 1408 1.1 liamjfoy struct ifaddr * 1409 1.1 liamjfoy carp_iamatch6(void *v, struct in6_addr *taddr) 1410 1.1 liamjfoy { 1411 1.1 liamjfoy struct carp_if *cif = v; 1412 1.1 liamjfoy struct carp_softc *vh; 1413 1.1 liamjfoy struct ifaddr *ifa; 1414 1.1 liamjfoy 1415 1.1 liamjfoy TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1416 1.93 ozaki int s = pserialize_read_enter(); 1417 1.74 ozaki IFADDR_READER_FOREACH(ifa, &vh->sc_if) { 1418 1.1 liamjfoy if (IN6_ARE_ADDR_EQUAL(taddr, 1419 1.1 liamjfoy &ifatoia6(ifa)->ia_addr.sin6_addr) && 1420 1.1 liamjfoy ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == 1421 1.1 liamjfoy (IFF_UP|IFF_RUNNING)) && vh->sc_state == MASTER) 1422 1.1 liamjfoy return (ifa); 1423 1.1 liamjfoy } 1424 1.93 ozaki pserialize_read_exit(s); 1425 1.1 liamjfoy } 1426 1.1 liamjfoy 1427 1.1 liamjfoy return (NULL); 1428 1.1 liamjfoy } 1429 1.1 liamjfoy #endif /* INET6 */ 1430 1.1 liamjfoy 1431 1.1 liamjfoy struct ifnet * 1432 1.1 liamjfoy carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src) 1433 1.1 liamjfoy { 1434 1.1 liamjfoy struct carp_if *cif = (struct carp_if *)v; 1435 1.1 liamjfoy struct carp_softc *vh; 1436 1.1 liamjfoy u_int8_t *ena; 1437 1.1 liamjfoy 1438 1.1 liamjfoy if (src) 1439 1.1 liamjfoy ena = (u_int8_t *)&eh->ether_shost; 1440 1.1 liamjfoy else 1441 1.1 liamjfoy ena = (u_int8_t *)&eh->ether_dhost; 1442 1.1 liamjfoy 1443 1.1 liamjfoy switch (iftype) { 1444 1.1 liamjfoy case IFT_ETHER: 1445 1.1 liamjfoy case IFT_FDDI: 1446 1.1 liamjfoy if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1) 1447 1.1 liamjfoy return (NULL); 1448 1.1 liamjfoy break; 1449 1.1 liamjfoy case IFT_ISO88025: 1450 1.1 liamjfoy if (ena[0] != 3 || ena[1] || ena[4] || ena[5]) 1451 1.1 liamjfoy return (NULL); 1452 1.1 liamjfoy break; 1453 1.1 liamjfoy default: 1454 1.1 liamjfoy return (NULL); 1455 1.1 liamjfoy break; 1456 1.1 liamjfoy } 1457 1.1 liamjfoy 1458 1.1 liamjfoy TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) 1459 1.1 liamjfoy if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == 1460 1.1 liamjfoy (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER && 1461 1.31 cegger !memcmp(ena, CLLADDR(vh->sc_if.if_sadl), 1462 1.1 liamjfoy ETHER_ADDR_LEN)) { 1463 1.1 liamjfoy return (&vh->sc_if); 1464 1.1 liamjfoy } 1465 1.1 liamjfoy 1466 1.1 liamjfoy return (NULL); 1467 1.1 liamjfoy } 1468 1.1 liamjfoy 1469 1.1 liamjfoy int 1470 1.1 liamjfoy carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) 1471 1.1 liamjfoy { 1472 1.1 liamjfoy struct ether_header eh; 1473 1.67 ozaki struct carp_if *cif = (struct carp_if *)m_get_rcvif_NOMPSAFE(m)->if_carp; 1474 1.1 liamjfoy struct ifnet *ifp; 1475 1.1 liamjfoy 1476 1.34 tsutsui memcpy(&eh.ether_shost, shost, sizeof(eh.ether_shost)); 1477 1.34 tsutsui memcpy(&eh.ether_dhost, dhost, sizeof(eh.ether_dhost)); 1478 1.1 liamjfoy eh.ether_type = etype; 1479 1.1 liamjfoy 1480 1.1 liamjfoy if (m->m_flags & (M_BCAST|M_MCAST)) { 1481 1.1 liamjfoy struct carp_softc *vh; 1482 1.1 liamjfoy struct mbuf *m0; 1483 1.1 liamjfoy 1484 1.1 liamjfoy /* 1485 1.1 liamjfoy * XXX Should really check the list of multicast addresses 1486 1.1 liamjfoy * for each CARP interface _before_ copying. 1487 1.1 liamjfoy */ 1488 1.1 liamjfoy TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { 1489 1.1 liamjfoy m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); 1490 1.1 liamjfoy if (m0 == NULL) 1491 1.1 liamjfoy continue; 1492 1.66 ozaki m_set_rcvif(m0, &vh->sc_if); 1493 1.1 liamjfoy ether_input(&vh->sc_if, m0); 1494 1.1 liamjfoy } 1495 1.1 liamjfoy return (1); 1496 1.1 liamjfoy } 1497 1.1 liamjfoy 1498 1.67 ozaki ifp = carp_ourether(cif, &eh, m_get_rcvif_NOMPSAFE(m)->if_type, 0); 1499 1.1 liamjfoy if (ifp == NULL) { 1500 1.1 liamjfoy return (1); 1501 1.1 liamjfoy } 1502 1.1 liamjfoy 1503 1.66 ozaki m_set_rcvif(m, ifp); 1504 1.1 liamjfoy 1505 1.99 msaitoh bpf_mtap(ifp, m, BPF_D_IN); 1506 1.108 thorpej if_statinc(ifp, if_ipackets); 1507 1.1 liamjfoy ether_input(ifp, m); 1508 1.1 liamjfoy return (0); 1509 1.1 liamjfoy } 1510 1.1 liamjfoy 1511 1.58 ozaki static void 1512 1.1 liamjfoy carp_master_down(void *v) 1513 1.1 liamjfoy { 1514 1.1 liamjfoy struct carp_softc *sc = v; 1515 1.1 liamjfoy 1516 1.1 liamjfoy switch (sc->sc_state) { 1517 1.1 liamjfoy case INIT: 1518 1.1 liamjfoy printf("%s: master_down event in INIT state\n", 1519 1.1 liamjfoy sc->sc_if.if_xname); 1520 1.1 liamjfoy break; 1521 1.1 liamjfoy case MASTER: 1522 1.1 liamjfoy break; 1523 1.1 liamjfoy case BACKUP: 1524 1.38 taca CARP_LOG(sc, ("INIT -> MASTER (preempting)")); 1525 1.1 liamjfoy carp_set_state(sc, MASTER); 1526 1.1 liamjfoy carp_send_ad(sc); 1527 1.1 liamjfoy carp_send_arp(sc); 1528 1.1 liamjfoy #ifdef INET6 1529 1.1 liamjfoy carp_send_na(sc); 1530 1.1 liamjfoy #endif /* INET6 */ 1531 1.1 liamjfoy carp_setrun(sc, 0); 1532 1.1 liamjfoy carp_setroute(sc, RTM_ADD); 1533 1.1 liamjfoy break; 1534 1.1 liamjfoy } 1535 1.1 liamjfoy } 1536 1.1 liamjfoy 1537 1.1 liamjfoy /* 1538 1.1 liamjfoy * When in backup state, af indicates whether to reset the master down timer 1539 1.1 liamjfoy * for v4 or v6. If it's set to zero, reset the ones which are already pending. 1540 1.1 liamjfoy */ 1541 1.58 ozaki static void 1542 1.1 liamjfoy carp_setrun(struct carp_softc *sc, sa_family_t af) 1543 1.1 liamjfoy { 1544 1.1 liamjfoy struct timeval tv; 1545 1.1 liamjfoy 1546 1.1 liamjfoy if (sc->sc_carpdev == NULL) { 1547 1.1 liamjfoy sc->sc_if.if_flags &= ~IFF_RUNNING; 1548 1.1 liamjfoy carp_set_state(sc, INIT); 1549 1.1 liamjfoy return; 1550 1.1 liamjfoy } 1551 1.1 liamjfoy 1552 1.1 liamjfoy if (sc->sc_if.if_flags & IFF_UP && sc->sc_vhid > 0 && 1553 1.1 liamjfoy (sc->sc_naddrs || sc->sc_naddrs6) && !sc->sc_suppress) { 1554 1.1 liamjfoy sc->sc_if.if_flags |= IFF_RUNNING; 1555 1.1 liamjfoy } else { 1556 1.1 liamjfoy sc->sc_if.if_flags &= ~IFF_RUNNING; 1557 1.1 liamjfoy carp_setroute(sc, RTM_DELETE); 1558 1.1 liamjfoy return; 1559 1.1 liamjfoy } 1560 1.1 liamjfoy 1561 1.1 liamjfoy switch (sc->sc_state) { 1562 1.1 liamjfoy case INIT: 1563 1.1 liamjfoy carp_set_state(sc, BACKUP); 1564 1.1 liamjfoy carp_setroute(sc, RTM_DELETE); 1565 1.1 liamjfoy carp_setrun(sc, 0); 1566 1.1 liamjfoy break; 1567 1.1 liamjfoy case BACKUP: 1568 1.1 liamjfoy callout_stop(&sc->sc_ad_tmo); 1569 1.1 liamjfoy tv.tv_sec = 3 * sc->sc_advbase; 1570 1.1 liamjfoy tv.tv_usec = sc->sc_advskew * 1000000 / 256; 1571 1.1 liamjfoy switch (af) { 1572 1.1 liamjfoy #ifdef INET 1573 1.1 liamjfoy case AF_INET: 1574 1.1 liamjfoy callout_schedule(&sc->sc_md_tmo, tvtohz(&tv)); 1575 1.1 liamjfoy break; 1576 1.1 liamjfoy #endif /* INET */ 1577 1.85 ozaki #ifdef INET6 1578 1.1 liamjfoy case AF_INET6: 1579 1.1 liamjfoy callout_schedule(&sc->sc_md6_tmo, tvtohz(&tv)); 1580 1.1 liamjfoy break; 1581 1.1 liamjfoy #endif /* INET6 */ 1582 1.1 liamjfoy default: 1583 1.1 liamjfoy if (sc->sc_naddrs) 1584 1.1 liamjfoy callout_schedule(&sc->sc_md_tmo, tvtohz(&tv)); 1585 1.85 ozaki #ifdef INET6 1586 1.1 liamjfoy if (sc->sc_naddrs6) 1587 1.1 liamjfoy callout_schedule(&sc->sc_md6_tmo, tvtohz(&tv)); 1588 1.75 is #endif /* INET6 */ 1589 1.1 liamjfoy break; 1590 1.1 liamjfoy } 1591 1.1 liamjfoy break; 1592 1.1 liamjfoy case MASTER: 1593 1.1 liamjfoy tv.tv_sec = sc->sc_advbase; 1594 1.1 liamjfoy tv.tv_usec = sc->sc_advskew * 1000000 / 256; 1595 1.1 liamjfoy callout_schedule(&sc->sc_ad_tmo, tvtohz(&tv)); 1596 1.1 liamjfoy break; 1597 1.1 liamjfoy } 1598 1.1 liamjfoy } 1599 1.1 liamjfoy 1600 1.58 ozaki static void 1601 1.1 liamjfoy carp_multicast_cleanup(struct carp_softc *sc) 1602 1.1 liamjfoy { 1603 1.1 liamjfoy struct ip_moptions *imo = &sc->sc_imo; 1604 1.1 liamjfoy #ifdef INET6 1605 1.1 liamjfoy struct ip6_moptions *im6o = &sc->sc_im6o; 1606 1.1 liamjfoy #endif 1607 1.1 liamjfoy u_int16_t n = imo->imo_num_memberships; 1608 1.1 liamjfoy 1609 1.1 liamjfoy /* Clean up our own multicast memberships */ 1610 1.1 liamjfoy while (n-- > 0) { 1611 1.1 liamjfoy if (imo->imo_membership[n] != NULL) { 1612 1.1 liamjfoy in_delmulti(imo->imo_membership[n]); 1613 1.1 liamjfoy imo->imo_membership[n] = NULL; 1614 1.1 liamjfoy } 1615 1.1 liamjfoy } 1616 1.1 liamjfoy imo->imo_num_memberships = 0; 1617 1.71 ozaki imo->imo_multicast_if_index = 0; 1618 1.1 liamjfoy 1619 1.1 liamjfoy #ifdef INET6 1620 1.1 liamjfoy while (!LIST_EMPTY(&im6o->im6o_memberships)) { 1621 1.1 liamjfoy struct in6_multi_mship *imm = 1622 1.1 liamjfoy LIST_FIRST(&im6o->im6o_memberships); 1623 1.1 liamjfoy 1624 1.1 liamjfoy LIST_REMOVE(imm, i6mm_chain); 1625 1.1 liamjfoy in6_leavegroup(imm); 1626 1.1 liamjfoy } 1627 1.71 ozaki im6o->im6o_multicast_if_index = 0; 1628 1.1 liamjfoy #endif 1629 1.1 liamjfoy 1630 1.1 liamjfoy /* And any other multicast memberships */ 1631 1.1 liamjfoy carp_ether_purgemulti(sc); 1632 1.1 liamjfoy } 1633 1.1 liamjfoy 1634 1.58 ozaki static int 1635 1.1 liamjfoy carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp) 1636 1.1 liamjfoy { 1637 1.1 liamjfoy struct carp_if *cif, *ncif = NULL; 1638 1.1 liamjfoy struct carp_softc *vr, *after = NULL; 1639 1.1 liamjfoy int myself = 0, error = 0; 1640 1.1 liamjfoy int s; 1641 1.1 liamjfoy 1642 1.1 liamjfoy if (ifp == sc->sc_carpdev) 1643 1.1 liamjfoy return (0); 1644 1.1 liamjfoy 1645 1.1 liamjfoy if (ifp != NULL) { 1646 1.1 liamjfoy if ((ifp->if_flags & IFF_MULTICAST) == 0) 1647 1.1 liamjfoy return (EADDRNOTAVAIL); 1648 1.1 liamjfoy 1649 1.1 liamjfoy if (ifp->if_type == IFT_CARP) 1650 1.1 liamjfoy return (EINVAL); 1651 1.1 liamjfoy 1652 1.1 liamjfoy if (ifp->if_carp == NULL) { 1653 1.104 chs ncif = malloc(sizeof(*cif), M_IFADDR, M_WAITOK); 1654 1.1 liamjfoy if ((error = ifpromisc(ifp, 1))) { 1655 1.28 cegger free(ncif, M_IFADDR); 1656 1.1 liamjfoy return (error); 1657 1.1 liamjfoy } 1658 1.1 liamjfoy 1659 1.1 liamjfoy ncif->vhif_ifp = ifp; 1660 1.1 liamjfoy TAILQ_INIT(&ncif->vhif_vrs); 1661 1.1 liamjfoy } else { 1662 1.1 liamjfoy cif = (struct carp_if *)ifp->if_carp; 1663 1.1 liamjfoy TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) 1664 1.1 liamjfoy if (vr != sc && vr->sc_vhid == sc->sc_vhid) 1665 1.1 liamjfoy return (EINVAL); 1666 1.1 liamjfoy } 1667 1.1 liamjfoy 1668 1.1 liamjfoy /* detach from old interface */ 1669 1.1 liamjfoy if (sc->sc_carpdev != NULL) 1670 1.1 liamjfoy carpdetach(sc); 1671 1.1 liamjfoy 1672 1.1 liamjfoy /* join multicast groups */ 1673 1.1 liamjfoy if (sc->sc_naddrs < 0 && 1674 1.1 liamjfoy (error = carp_join_multicast(sc)) != 0) { 1675 1.1 liamjfoy if (ncif != NULL) 1676 1.28 cegger free(ncif, M_IFADDR); 1677 1.1 liamjfoy return (error); 1678 1.1 liamjfoy } 1679 1.1 liamjfoy 1680 1.1 liamjfoy #ifdef INET6 1681 1.1 liamjfoy if (sc->sc_naddrs6 < 0 && 1682 1.1 liamjfoy (error = carp_join_multicast6(sc)) != 0) { 1683 1.1 liamjfoy if (ncif != NULL) 1684 1.28 cegger free(ncif, M_IFADDR); 1685 1.1 liamjfoy carp_multicast_cleanup(sc); 1686 1.1 liamjfoy return (error); 1687 1.1 liamjfoy } 1688 1.1 liamjfoy #endif 1689 1.1 liamjfoy 1690 1.1 liamjfoy /* attach carp interface to physical interface */ 1691 1.1 liamjfoy if (ncif != NULL) 1692 1.12 christos ifp->if_carp = (void *)ncif; 1693 1.1 liamjfoy sc->sc_carpdev = ifp; 1694 1.49 bouyer sc->sc_if.if_capabilities = ifp->if_capabilities & 1695 1.49 bouyer (IFCAP_TSOv4 | IFCAP_TSOv6 | 1696 1.49 bouyer IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx| 1697 1.49 bouyer IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx| 1698 1.49 bouyer IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx| 1699 1.49 bouyer IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx| 1700 1.49 bouyer IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx); 1701 1.49 bouyer 1702 1.1 liamjfoy cif = (struct carp_if *)ifp->if_carp; 1703 1.1 liamjfoy TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) { 1704 1.1 liamjfoy if (vr == sc) 1705 1.1 liamjfoy myself = 1; 1706 1.1 liamjfoy if (vr->sc_vhid < sc->sc_vhid) 1707 1.1 liamjfoy after = vr; 1708 1.1 liamjfoy } 1709 1.1 liamjfoy 1710 1.1 liamjfoy if (!myself) { 1711 1.1 liamjfoy /* We're trying to keep things in order */ 1712 1.1 liamjfoy if (after == NULL) { 1713 1.1 liamjfoy TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list); 1714 1.1 liamjfoy } else { 1715 1.1 liamjfoy TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, 1716 1.1 liamjfoy sc, sc_list); 1717 1.1 liamjfoy } 1718 1.1 liamjfoy cif->vhif_nvrs++; 1719 1.1 liamjfoy } 1720 1.1 liamjfoy if (sc->sc_naddrs || sc->sc_naddrs6) 1721 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 1722 1.1 liamjfoy carp_set_enaddr(sc); 1723 1.116 yamaguch sc->sc_linkstate_hook = if_linkstate_change_establish(ifp, 1724 1.116 yamaguch carp_carpdev_state, (void *)ifp); 1725 1.54 bouyer KERNEL_LOCK(1, NULL); 1726 1.1 liamjfoy s = splnet(); 1727 1.1 liamjfoy carp_carpdev_state(ifp); 1728 1.1 liamjfoy splx(s); 1729 1.54 bouyer KERNEL_UNLOCK_ONE(NULL); 1730 1.1 liamjfoy } else { 1731 1.1 liamjfoy carpdetach(sc); 1732 1.1 liamjfoy sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 1733 1.1 liamjfoy } 1734 1.1 liamjfoy return (0); 1735 1.1 liamjfoy } 1736 1.1 liamjfoy 1737 1.58 ozaki static void 1738 1.1 liamjfoy carp_set_enaddr(struct carp_softc *sc) 1739 1.1 liamjfoy { 1740 1.114 roy struct ifnet *ifp = &sc->sc_if; 1741 1.16 dyoung uint8_t enaddr[ETHER_ADDR_LEN]; 1742 1.114 roy 1743 1.114 roy if (sc->sc_vhid == -1) { 1744 1.114 roy ifp->if_addrlen = 0; 1745 1.114 roy if_alloc_sadl(ifp); 1746 1.114 roy return; 1747 1.114 roy } 1748 1.114 roy 1749 1.1 liamjfoy if (sc->sc_carpdev && sc->sc_carpdev->if_type == IFT_ISO88025) { 1750 1.16 dyoung enaddr[0] = 3; 1751 1.16 dyoung enaddr[1] = 0; 1752 1.16 dyoung enaddr[2] = 0x40 >> (sc->sc_vhid - 1); 1753 1.16 dyoung enaddr[3] = 0x40000 >> (sc->sc_vhid - 1); 1754 1.16 dyoung enaddr[4] = 0; 1755 1.16 dyoung enaddr[5] = 0; 1756 1.1 liamjfoy } else { 1757 1.16 dyoung enaddr[0] = 0; 1758 1.16 dyoung enaddr[1] = 0; 1759 1.16 dyoung enaddr[2] = 0x5e; 1760 1.16 dyoung enaddr[3] = 0; 1761 1.16 dyoung enaddr[4] = 1; 1762 1.16 dyoung enaddr[5] = sc->sc_vhid; 1763 1.1 liamjfoy } 1764 1.114 roy 1765 1.114 roy if_set_sadl(ifp, enaddr, sizeof(enaddr), false); 1766 1.1 liamjfoy } 1767 1.1 liamjfoy 1768 1.58 ozaki #if 0 1769 1.58 ozaki static void 1770 1.1 liamjfoy carp_addr_updated(void *v) 1771 1.1 liamjfoy { 1772 1.1 liamjfoy struct carp_softc *sc = (struct carp_softc *) v; 1773 1.1 liamjfoy struct ifaddr *ifa; 1774 1.1 liamjfoy int new_naddrs = 0, new_naddrs6 = 0; 1775 1.1 liamjfoy 1776 1.74 ozaki IFADDR_READER_FOREACH(ifa, &sc->sc_if) { 1777 1.1 liamjfoy if (ifa->ifa_addr->sa_family == AF_INET) 1778 1.1 liamjfoy new_naddrs++; 1779 1.1 liamjfoy else if (ifa->ifa_addr->sa_family == AF_INET6) 1780 1.1 liamjfoy new_naddrs6++; 1781 1.1 liamjfoy } 1782 1.1 liamjfoy 1783 1.1 liamjfoy /* Handle a callback after SIOCDIFADDR */ 1784 1.1 liamjfoy if (new_naddrs < sc->sc_naddrs || new_naddrs6 < sc->sc_naddrs6) { 1785 1.1 liamjfoy struct in_addr mc_addr; 1786 1.1 liamjfoy 1787 1.1 liamjfoy sc->sc_naddrs = new_naddrs; 1788 1.1 liamjfoy sc->sc_naddrs6 = new_naddrs6; 1789 1.1 liamjfoy 1790 1.1 liamjfoy /* Re-establish multicast membership removed by in_control */ 1791 1.1 liamjfoy mc_addr.s_addr = INADDR_CARP_GROUP; 1792 1.56 rmind if (!in_multi_group(mc_addr, &sc->sc_if, 0)) { 1793 1.32 cegger memset(&sc->sc_imo, 0, sizeof(sc->sc_imo)); 1794 1.1 liamjfoy 1795 1.1 liamjfoy if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0) 1796 1.1 liamjfoy carp_join_multicast(sc); 1797 1.1 liamjfoy } 1798 1.1 liamjfoy 1799 1.1 liamjfoy if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) { 1800 1.1 liamjfoy sc->sc_if.if_flags &= ~IFF_UP; 1801 1.1 liamjfoy carp_set_state(sc, INIT); 1802 1.1 liamjfoy } else 1803 1.1 liamjfoy carp_hmac_prepare(sc); 1804 1.1 liamjfoy } 1805 1.1 liamjfoy 1806 1.1 liamjfoy carp_setrun(sc, 0); 1807 1.1 liamjfoy } 1808 1.58 ozaki #endif 1809 1.1 liamjfoy 1810 1.58 ozaki static int 1811 1.1 liamjfoy carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) 1812 1.1 liamjfoy { 1813 1.1 liamjfoy struct ifnet *ifp = sc->sc_carpdev; 1814 1.1 liamjfoy struct in_ifaddr *ia, *ia_if; 1815 1.1 liamjfoy int error = 0; 1816 1.77 ozaki int s; 1817 1.1 liamjfoy 1818 1.1 liamjfoy if (sin->sin_addr.s_addr == 0) { 1819 1.1 liamjfoy if (!(sc->sc_if.if_flags & IFF_UP)) 1820 1.1 liamjfoy carp_set_state(sc, INIT); 1821 1.1 liamjfoy if (sc->sc_naddrs) 1822 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 1823 1.1 liamjfoy carp_setrun(sc, 0); 1824 1.1 liamjfoy return (0); 1825 1.1 liamjfoy } 1826 1.1 liamjfoy 1827 1.1 liamjfoy /* we have to do this by hand to ensure we don't match on ourselves */ 1828 1.1 liamjfoy ia_if = NULL; 1829 1.77 ozaki s = pserialize_read_enter(); 1830 1.73 ozaki IN_ADDRLIST_READER_FOREACH(ia) { 1831 1.1 liamjfoy /* and, yeah, we need a multicast-capable iface too */ 1832 1.1 liamjfoy if (ia->ia_ifp != &sc->sc_if && 1833 1.1 liamjfoy ia->ia_ifp->if_type != IFT_CARP && 1834 1.1 liamjfoy (ia->ia_ifp->if_flags & IFF_MULTICAST) && 1835 1.1 liamjfoy (sin->sin_addr.s_addr & ia->ia_subnetmask) == 1836 1.1 liamjfoy ia->ia_subnet) { 1837 1.1 liamjfoy if (!ia_if) 1838 1.1 liamjfoy ia_if = ia; 1839 1.1 liamjfoy } 1840 1.1 liamjfoy } 1841 1.1 liamjfoy 1842 1.1 liamjfoy if (ia_if) { 1843 1.1 liamjfoy ia = ia_if; 1844 1.1 liamjfoy if (ifp) { 1845 1.1 liamjfoy if (ifp != ia->ia_ifp) 1846 1.1 liamjfoy return (EADDRNOTAVAIL); 1847 1.1 liamjfoy } else { 1848 1.77 ozaki /* FIXME NOMPSAFE */ 1849 1.1 liamjfoy ifp = ia->ia_ifp; 1850 1.1 liamjfoy } 1851 1.1 liamjfoy } 1852 1.77 ozaki pserialize_read_exit(s); 1853 1.1 liamjfoy 1854 1.1 liamjfoy if ((error = carp_set_ifp(sc, ifp))) 1855 1.1 liamjfoy return (error); 1856 1.1 liamjfoy 1857 1.1 liamjfoy if (sc->sc_carpdev == NULL) 1858 1.1 liamjfoy return (EADDRNOTAVAIL); 1859 1.1 liamjfoy 1860 1.1 liamjfoy if (sc->sc_naddrs == 0 && (error = carp_join_multicast(sc)) != 0) 1861 1.1 liamjfoy return (error); 1862 1.1 liamjfoy 1863 1.1 liamjfoy sc->sc_naddrs++; 1864 1.1 liamjfoy if (sc->sc_carpdev != NULL) 1865 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 1866 1.1 liamjfoy 1867 1.1 liamjfoy carp_set_state(sc, INIT); 1868 1.1 liamjfoy carp_setrun(sc, 0); 1869 1.1 liamjfoy 1870 1.1 liamjfoy /* 1871 1.1 liamjfoy * Hook if_addrhooks so that we get a callback after in_ifinit has run, 1872 1.1 liamjfoy * to correct any inappropriate routes that it inserted. 1873 1.1 liamjfoy */ 1874 1.1 liamjfoy if (sc->ah_cookie == 0) { 1875 1.1 liamjfoy /* XXX link address hook */ 1876 1.1 liamjfoy } 1877 1.1 liamjfoy 1878 1.1 liamjfoy return (0); 1879 1.1 liamjfoy } 1880 1.1 liamjfoy 1881 1.58 ozaki static int 1882 1.1 liamjfoy carp_join_multicast(struct carp_softc *sc) 1883 1.1 liamjfoy { 1884 1.121 rin struct ip_moptions *imo = &sc->sc_imo; 1885 1.121 rin struct in_multi *imm; 1886 1.1 liamjfoy struct in_addr addr; 1887 1.1 liamjfoy 1888 1.118 mlelstv if (sc->sc_carpdev == NULL) 1889 1.118 mlelstv return (ENETDOWN); 1890 1.118 mlelstv 1891 1.1 liamjfoy addr.s_addr = INADDR_CARP_GROUP; 1892 1.121 rin if ((imm = in_addmulti(&addr, &sc->sc_if)) == NULL) 1893 1.1 liamjfoy return (ENOBUFS); 1894 1.1 liamjfoy 1895 1.121 rin imo->imo_membership[0] = imm; 1896 1.1 liamjfoy imo->imo_num_memberships = 1; 1897 1.118 mlelstv imo->imo_multicast_if_index = sc->sc_carpdev->if_index; 1898 1.1 liamjfoy imo->imo_multicast_ttl = CARP_DFLTTL; 1899 1.1 liamjfoy imo->imo_multicast_loop = 0; 1900 1.1 liamjfoy return (0); 1901 1.1 liamjfoy } 1902 1.1 liamjfoy 1903 1.1 liamjfoy 1904 1.1 liamjfoy #ifdef INET6 1905 1.58 ozaki static int 1906 1.1 liamjfoy carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) 1907 1.1 liamjfoy { 1908 1.1 liamjfoy struct ifnet *ifp = sc->sc_carpdev; 1909 1.1 liamjfoy struct in6_ifaddr *ia, *ia_if; 1910 1.1 liamjfoy int error = 0; 1911 1.77 ozaki int s; 1912 1.1 liamjfoy 1913 1.1 liamjfoy if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1914 1.1 liamjfoy if (!(sc->sc_if.if_flags & IFF_UP)) 1915 1.1 liamjfoy carp_set_state(sc, INIT); 1916 1.1 liamjfoy if (sc->sc_naddrs6) 1917 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 1918 1.1 liamjfoy carp_setrun(sc, 0); 1919 1.1 liamjfoy return (0); 1920 1.1 liamjfoy } 1921 1.1 liamjfoy 1922 1.1 liamjfoy /* we have to do this by hand to ensure we don't match on ourselves */ 1923 1.1 liamjfoy ia_if = NULL; 1924 1.77 ozaki s = pserialize_read_enter(); 1925 1.72 ozaki IN6_ADDRLIST_READER_FOREACH(ia) { 1926 1.1 liamjfoy int i; 1927 1.1 liamjfoy 1928 1.1 liamjfoy for (i = 0; i < 4; i++) { 1929 1.1 liamjfoy if ((sin6->sin6_addr.s6_addr32[i] & 1930 1.1 liamjfoy ia->ia_prefixmask.sin6_addr.s6_addr32[i]) != 1931 1.1 liamjfoy (ia->ia_addr.sin6_addr.s6_addr32[i] & 1932 1.1 liamjfoy ia->ia_prefixmask.sin6_addr.s6_addr32[i])) 1933 1.1 liamjfoy break; 1934 1.1 liamjfoy } 1935 1.1 liamjfoy /* and, yeah, we need a multicast-capable iface too */ 1936 1.1 liamjfoy if (ia->ia_ifp != &sc->sc_if && 1937 1.1 liamjfoy ia->ia_ifp->if_type != IFT_CARP && 1938 1.1 liamjfoy (ia->ia_ifp->if_flags & IFF_MULTICAST) && 1939 1.1 liamjfoy (i == 4)) { 1940 1.1 liamjfoy if (!ia_if) 1941 1.1 liamjfoy ia_if = ia; 1942 1.1 liamjfoy } 1943 1.1 liamjfoy } 1944 1.77 ozaki pserialize_read_exit(s); 1945 1.1 liamjfoy 1946 1.1 liamjfoy if (ia_if) { 1947 1.1 liamjfoy ia = ia_if; 1948 1.1 liamjfoy if (sc->sc_carpdev) { 1949 1.1 liamjfoy if (sc->sc_carpdev != ia->ia_ifp) 1950 1.1 liamjfoy return (EADDRNOTAVAIL); 1951 1.1 liamjfoy } else { 1952 1.1 liamjfoy ifp = ia->ia_ifp; 1953 1.1 liamjfoy } 1954 1.1 liamjfoy } 1955 1.1 liamjfoy 1956 1.1 liamjfoy if ((error = carp_set_ifp(sc, ifp))) 1957 1.1 liamjfoy return (error); 1958 1.1 liamjfoy 1959 1.1 liamjfoy if (sc->sc_carpdev == NULL) 1960 1.1 liamjfoy return (EADDRNOTAVAIL); 1961 1.1 liamjfoy 1962 1.1 liamjfoy if (sc->sc_naddrs6 == 0 && (error = carp_join_multicast6(sc)) != 0) 1963 1.1 liamjfoy return (error); 1964 1.1 liamjfoy 1965 1.1 liamjfoy sc->sc_naddrs6++; 1966 1.1 liamjfoy if (sc->sc_carpdev != NULL) 1967 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 1968 1.1 liamjfoy carp_set_state(sc, INIT); 1969 1.1 liamjfoy carp_setrun(sc, 0); 1970 1.1 liamjfoy 1971 1.1 liamjfoy return (0); 1972 1.1 liamjfoy } 1973 1.1 liamjfoy 1974 1.58 ozaki static int 1975 1.1 liamjfoy carp_join_multicast6(struct carp_softc *sc) 1976 1.1 liamjfoy { 1977 1.1 liamjfoy struct in6_multi_mship *imm, *imm2; 1978 1.1 liamjfoy struct ip6_moptions *im6o = &sc->sc_im6o; 1979 1.1 liamjfoy struct sockaddr_in6 addr6; 1980 1.1 liamjfoy int error; 1981 1.1 liamjfoy 1982 1.118 mlelstv if (sc->sc_carpdev == NULL) 1983 1.118 mlelstv return (ENETDOWN); 1984 1.118 mlelstv 1985 1.1 liamjfoy /* Join IPv6 CARP multicast group */ 1986 1.32 cegger memset(&addr6, 0, sizeof(addr6)); 1987 1.1 liamjfoy addr6.sin6_family = AF_INET6; 1988 1.1 liamjfoy addr6.sin6_len = sizeof(addr6); 1989 1.1 liamjfoy addr6.sin6_addr.s6_addr16[0] = htons(0xff02); 1990 1.1 liamjfoy addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index); 1991 1.1 liamjfoy addr6.sin6_addr.s6_addr8[15] = 0x12; 1992 1.1 liamjfoy if ((imm = in6_joingroup(&sc->sc_if, 1993 1.1 liamjfoy &addr6.sin6_addr, &error, 0)) == NULL) { 1994 1.1 liamjfoy return (error); 1995 1.1 liamjfoy } 1996 1.1 liamjfoy /* join solicited multicast address */ 1997 1.32 cegger memset(&addr6.sin6_addr, 0, sizeof(addr6.sin6_addr)); 1998 1.1 liamjfoy addr6.sin6_addr.s6_addr16[0] = htons(0xff02); 1999 1.1 liamjfoy addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index); 2000 1.1 liamjfoy addr6.sin6_addr.s6_addr32[1] = 0; 2001 1.1 liamjfoy addr6.sin6_addr.s6_addr32[2] = htonl(1); 2002 1.1 liamjfoy addr6.sin6_addr.s6_addr32[3] = 0; 2003 1.1 liamjfoy addr6.sin6_addr.s6_addr8[12] = 0xff; 2004 1.1 liamjfoy if ((imm2 = in6_joingroup(&sc->sc_if, 2005 1.1 liamjfoy &addr6.sin6_addr, &error, 0)) == NULL) { 2006 1.1 liamjfoy in6_leavegroup(imm); 2007 1.1 liamjfoy return (error); 2008 1.1 liamjfoy } 2009 1.1 liamjfoy 2010 1.1 liamjfoy /* apply v6 multicast membership */ 2011 1.118 mlelstv im6o->im6o_multicast_if_index = sc->sc_carpdev->if_index; 2012 1.1 liamjfoy if (imm) 2013 1.1 liamjfoy LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, 2014 1.1 liamjfoy i6mm_chain); 2015 1.1 liamjfoy if (imm2) 2016 1.1 liamjfoy LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2, 2017 1.1 liamjfoy i6mm_chain); 2018 1.1 liamjfoy 2019 1.1 liamjfoy return (0); 2020 1.1 liamjfoy } 2021 1.1 liamjfoy 2022 1.1 liamjfoy #endif /* INET6 */ 2023 1.1 liamjfoy 2024 1.58 ozaki static int 2025 1.27 dyoung carp_ioctl(struct ifnet *ifp, u_long cmd, void *data) 2026 1.1 liamjfoy { 2027 1.5 ad struct lwp *l = curlwp; /* XXX */ 2028 1.1 liamjfoy struct carp_softc *sc = ifp->if_softc, *vr; 2029 1.1 liamjfoy struct carpreq carpr; 2030 1.1 liamjfoy struct ifaddr *ifa; 2031 1.1 liamjfoy struct ifreq *ifr; 2032 1.1 liamjfoy struct ifnet *cdev = NULL; 2033 1.1 liamjfoy int error = 0; 2034 1.1 liamjfoy 2035 1.27 dyoung ifa = (struct ifaddr *)data; 2036 1.27 dyoung ifr = (struct ifreq *)data; 2037 1.1 liamjfoy 2038 1.1 liamjfoy switch (cmd) { 2039 1.27 dyoung case SIOCINITIFADDR: 2040 1.1 liamjfoy switch (ifa->ifa_addr->sa_family) { 2041 1.1 liamjfoy #ifdef INET 2042 1.1 liamjfoy case AF_INET: 2043 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 2044 1.34 tsutsui memcpy(ifa->ifa_dstaddr, ifa->ifa_addr, 2045 1.1 liamjfoy sizeof(struct sockaddr)); 2046 1.1 liamjfoy error = carp_set_addr(sc, satosin(ifa->ifa_addr)); 2047 1.1 liamjfoy break; 2048 1.1 liamjfoy #endif /* INET */ 2049 1.1 liamjfoy #ifdef INET6 2050 1.1 liamjfoy case AF_INET6: 2051 1.1 liamjfoy sc->sc_if.if_flags|= IFF_UP; 2052 1.1 liamjfoy error = carp_set_addr6(sc, satosin6(ifa->ifa_addr)); 2053 1.1 liamjfoy break; 2054 1.1 liamjfoy #endif /* INET6 */ 2055 1.1 liamjfoy default: 2056 1.1 liamjfoy error = EAFNOSUPPORT; 2057 1.1 liamjfoy break; 2058 1.1 liamjfoy } 2059 1.1 liamjfoy break; 2060 1.1 liamjfoy 2061 1.1 liamjfoy case SIOCSIFFLAGS: 2062 1.27 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 2063 1.27 dyoung break; 2064 1.1 liamjfoy if (sc->sc_state != INIT && !(ifr->ifr_flags & IFF_UP)) { 2065 1.1 liamjfoy callout_stop(&sc->sc_ad_tmo); 2066 1.1 liamjfoy callout_stop(&sc->sc_md_tmo); 2067 1.1 liamjfoy callout_stop(&sc->sc_md6_tmo); 2068 1.1 liamjfoy if (sc->sc_state == MASTER) { 2069 1.1 liamjfoy /* we need the interface up to bow out */ 2070 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 2071 1.1 liamjfoy sc->sc_bow_out = 1; 2072 1.1 liamjfoy carp_send_ad(sc); 2073 1.1 liamjfoy } 2074 1.1 liamjfoy sc->sc_if.if_flags &= ~IFF_UP; 2075 1.1 liamjfoy carp_set_state(sc, INIT); 2076 1.1 liamjfoy carp_setrun(sc, 0); 2077 1.1 liamjfoy } else if (sc->sc_state == INIT && (ifr->ifr_flags & IFF_UP)) { 2078 1.1 liamjfoy sc->sc_if.if_flags |= IFF_UP; 2079 1.1 liamjfoy carp_setrun(sc, 0); 2080 1.1 liamjfoy } 2081 1.105 kardel carp_update_link_state(sc); 2082 1.1 liamjfoy break; 2083 1.1 liamjfoy 2084 1.1 liamjfoy case SIOCSVH: 2085 1.8 elad if (l == NULL) 2086 1.8 elad break; 2087 1.8 elad if ((error = kauth_authorize_network(l->l_cred, 2088 1.8 elad KAUTH_NETWORK_INTERFACE, 2089 1.9 christos KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 2090 1.8 elad NULL)) != 0) 2091 1.1 liamjfoy break; 2092 1.1 liamjfoy if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr))) 2093 1.1 liamjfoy break; 2094 1.1 liamjfoy error = 1; 2095 1.1 liamjfoy if (carpr.carpr_carpdev[0] != '\0' && 2096 1.1 liamjfoy (cdev = ifunit(carpr.carpr_carpdev)) == NULL) 2097 1.1 liamjfoy return (EINVAL); 2098 1.1 liamjfoy if ((error = carp_set_ifp(sc, cdev))) 2099 1.1 liamjfoy return (error); 2100 1.1 liamjfoy if (sc->sc_state != INIT && carpr.carpr_state != sc->sc_state) { 2101 1.1 liamjfoy switch (carpr.carpr_state) { 2102 1.1 liamjfoy case BACKUP: 2103 1.1 liamjfoy callout_stop(&sc->sc_ad_tmo); 2104 1.1 liamjfoy carp_set_state(sc, BACKUP); 2105 1.1 liamjfoy carp_setrun(sc, 0); 2106 1.1 liamjfoy carp_setroute(sc, RTM_DELETE); 2107 1.1 liamjfoy break; 2108 1.1 liamjfoy case MASTER: 2109 1.1 liamjfoy carp_master_down(sc); 2110 1.1 liamjfoy break; 2111 1.1 liamjfoy default: 2112 1.1 liamjfoy break; 2113 1.1 liamjfoy } 2114 1.1 liamjfoy } 2115 1.1 liamjfoy if (carpr.carpr_vhid > 0) { 2116 1.1 liamjfoy if (carpr.carpr_vhid > 255) { 2117 1.1 liamjfoy error = EINVAL; 2118 1.1 liamjfoy break; 2119 1.1 liamjfoy } 2120 1.1 liamjfoy if (sc->sc_carpdev) { 2121 1.1 liamjfoy struct carp_if *cif; 2122 1.1 liamjfoy cif = (struct carp_if *)sc->sc_carpdev->if_carp; 2123 1.1 liamjfoy TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) 2124 1.1 liamjfoy if (vr != sc && 2125 1.1 liamjfoy vr->sc_vhid == carpr.carpr_vhid) 2126 1.1 liamjfoy return (EINVAL); 2127 1.1 liamjfoy } 2128 1.1 liamjfoy sc->sc_vhid = carpr.carpr_vhid; 2129 1.1 liamjfoy carp_set_enaddr(sc); 2130 1.1 liamjfoy carp_set_state(sc, INIT); 2131 1.1 liamjfoy error--; 2132 1.1 liamjfoy } 2133 1.1 liamjfoy if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) { 2134 1.1 liamjfoy if (carpr.carpr_advskew > 254) { 2135 1.1 liamjfoy error = EINVAL; 2136 1.1 liamjfoy break; 2137 1.1 liamjfoy } 2138 1.1 liamjfoy if (carpr.carpr_advbase > 255) { 2139 1.1 liamjfoy error = EINVAL; 2140 1.1 liamjfoy break; 2141 1.1 liamjfoy } 2142 1.1 liamjfoy sc->sc_advbase = carpr.carpr_advbase; 2143 1.1 liamjfoy sc->sc_advskew = carpr.carpr_advskew; 2144 1.1 liamjfoy error--; 2145 1.1 liamjfoy } 2146 1.34 tsutsui memcpy(sc->sc_key, carpr.carpr_key, sizeof(sc->sc_key)); 2147 1.1 liamjfoy if (error > 0) 2148 1.1 liamjfoy error = EINVAL; 2149 1.1 liamjfoy else { 2150 1.1 liamjfoy error = 0; 2151 1.1 liamjfoy carp_setrun(sc, 0); 2152 1.1 liamjfoy } 2153 1.1 liamjfoy break; 2154 1.1 liamjfoy 2155 1.1 liamjfoy case SIOCGVH: 2156 1.32 cegger memset(&carpr, 0, sizeof(carpr)); 2157 1.1 liamjfoy if (sc->sc_carpdev != NULL) 2158 1.1 liamjfoy strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname, 2159 1.1 liamjfoy IFNAMSIZ); 2160 1.1 liamjfoy carpr.carpr_state = sc->sc_state; 2161 1.1 liamjfoy carpr.carpr_vhid = sc->sc_vhid; 2162 1.1 liamjfoy carpr.carpr_advbase = sc->sc_advbase; 2163 1.1 liamjfoy carpr.carpr_advskew = sc->sc_advskew; 2164 1.3 liamjfoy 2165 1.36 elad if ((l != NULL) && (error = kauth_authorize_network(l->l_cred, 2166 1.8 elad KAUTH_NETWORK_INTERFACE, 2167 1.9 christos KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 2168 1.35 elad NULL)) == 0) 2169 1.34 tsutsui memcpy(carpr.carpr_key, sc->sc_key, 2170 1.1 liamjfoy sizeof(carpr.carpr_key)); 2171 1.1 liamjfoy error = copyout(&carpr, ifr->ifr_data, sizeof(carpr)); 2172 1.1 liamjfoy break; 2173 1.1 liamjfoy 2174 1.1 liamjfoy case SIOCADDMULTI: 2175 1.1 liamjfoy error = carp_ether_addmulti(sc, ifr); 2176 1.1 liamjfoy break; 2177 1.1 liamjfoy 2178 1.1 liamjfoy case SIOCDELMULTI: 2179 1.1 liamjfoy error = carp_ether_delmulti(sc, ifr); 2180 1.1 liamjfoy break; 2181 1.1 liamjfoy 2182 1.49 bouyer case SIOCSIFCAP: 2183 1.50 christos if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) 2184 1.49 bouyer error = 0; 2185 1.49 bouyer break; 2186 1.49 bouyer 2187 1.1 liamjfoy default: 2188 1.27 dyoung error = ether_ioctl(ifp, cmd, data); 2189 1.1 liamjfoy } 2190 1.1 liamjfoy 2191 1.1 liamjfoy carp_hmac_prepare(sc); 2192 1.1 liamjfoy return (error); 2193 1.1 liamjfoy } 2194 1.1 liamjfoy 2195 1.1 liamjfoy 2196 1.1 liamjfoy /* 2197 1.1 liamjfoy * Start output on carp interface. This function should never be called. 2198 1.1 liamjfoy */ 2199 1.58 ozaki static void 2200 1.1 liamjfoy carp_start(struct ifnet *ifp) 2201 1.1 liamjfoy { 2202 1.1 liamjfoy #ifdef DEBUG 2203 1.1 liamjfoy printf("%s: start called\n", ifp->if_xname); 2204 1.1 liamjfoy #endif 2205 1.1 liamjfoy } 2206 1.1 liamjfoy 2207 1.1 liamjfoy int 2208 1.11 dyoung carp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, 2209 1.64 ozaki const struct rtentry *rt) 2210 1.1 liamjfoy { 2211 1.1 liamjfoy struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc); 2212 1.54 bouyer KASSERT(KERNEL_LOCKED_P()); 2213 1.1 liamjfoy 2214 1.1 liamjfoy if (sc->sc_carpdev != NULL && sc->sc_state == MASTER) { 2215 1.70 knakahar return if_output_lock(sc->sc_carpdev, ifp, m, sa, rt); 2216 1.1 liamjfoy } else { 2217 1.1 liamjfoy m_freem(m); 2218 1.1 liamjfoy return (ENETUNREACH); 2219 1.1 liamjfoy } 2220 1.1 liamjfoy } 2221 1.1 liamjfoy 2222 1.58 ozaki static void 2223 1.1 liamjfoy carp_set_state(struct carp_softc *sc, int state) 2224 1.1 liamjfoy { 2225 1.37 christos static const char *carp_states[] = { CARP_STATES }; 2226 1.88 roy 2227 1.1 liamjfoy if (sc->sc_state == state) 2228 1.1 liamjfoy return; 2229 1.1 liamjfoy 2230 1.37 christos CARP_LOG(sc, ("state transition from: %s -> to: %s", carp_states[sc->sc_state], carp_states[state])); 2231 1.37 christos 2232 1.1 liamjfoy sc->sc_state = state; 2233 1.105 kardel carp_update_link_state(sc); 2234 1.105 kardel } 2235 1.105 kardel 2236 1.105 kardel static void 2237 1.105 kardel carp_update_link_state(struct carp_softc *sc) 2238 1.105 kardel { 2239 1.105 kardel int link_state; 2240 1.105 kardel 2241 1.105 kardel switch (sc->sc_state) { 2242 1.1 liamjfoy case BACKUP: 2243 1.88 roy link_state = LINK_STATE_DOWN; 2244 1.1 liamjfoy break; 2245 1.1 liamjfoy case MASTER: 2246 1.88 roy link_state = LINK_STATE_UP; 2247 1.1 liamjfoy break; 2248 1.1 liamjfoy default: 2249 1.113 roy /* Not useable, so down makes perfect sense. */ 2250 1.113 roy link_state = LINK_STATE_DOWN; 2251 1.1 liamjfoy break; 2252 1.1 liamjfoy } 2253 1.110 thorpej if_link_state_change(&sc->sc_if, link_state); 2254 1.1 liamjfoy } 2255 1.1 liamjfoy 2256 1.1 liamjfoy void 2257 1.1 liamjfoy carp_carpdev_state(void *v) 2258 1.1 liamjfoy { 2259 1.1 liamjfoy struct carp_if *cif; 2260 1.1 liamjfoy struct carp_softc *sc; 2261 1.1 liamjfoy struct ifnet *ifp = v; 2262 1.1 liamjfoy 2263 1.1 liamjfoy if (ifp->if_type == IFT_CARP) 2264 1.1 liamjfoy return; 2265 1.1 liamjfoy 2266 1.1 liamjfoy cif = (struct carp_if *)ifp->if_carp; 2267 1.1 liamjfoy 2268 1.1 liamjfoy TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) { 2269 1.1 liamjfoy int suppressed = sc->sc_suppress; 2270 1.1 liamjfoy 2271 1.1 liamjfoy if (sc->sc_carpdev->if_link_state == LINK_STATE_DOWN || 2272 1.1 liamjfoy !(sc->sc_carpdev->if_flags & IFF_UP)) { 2273 1.1 liamjfoy sc->sc_if.if_flags &= ~IFF_RUNNING; 2274 1.1 liamjfoy callout_stop(&sc->sc_ad_tmo); 2275 1.1 liamjfoy callout_stop(&sc->sc_md_tmo); 2276 1.1 liamjfoy callout_stop(&sc->sc_md6_tmo); 2277 1.1 liamjfoy carp_set_state(sc, INIT); 2278 1.1 liamjfoy sc->sc_suppress = 1; 2279 1.1 liamjfoy carp_setrun(sc, 0); 2280 1.1 liamjfoy if (!suppressed) { 2281 1.1 liamjfoy carp_suppress_preempt++; 2282 1.1 liamjfoy if (carp_suppress_preempt == 1) 2283 1.1 liamjfoy carp_send_ad_all(); 2284 1.1 liamjfoy } 2285 1.1 liamjfoy } else { 2286 1.1 liamjfoy carp_set_state(sc, INIT); 2287 1.1 liamjfoy sc->sc_suppress = 0; 2288 1.1 liamjfoy carp_setrun(sc, 0); 2289 1.1 liamjfoy if (suppressed) 2290 1.1 liamjfoy carp_suppress_preempt--; 2291 1.1 liamjfoy } 2292 1.1 liamjfoy } 2293 1.1 liamjfoy } 2294 1.1 liamjfoy 2295 1.58 ozaki static int 2296 1.1 liamjfoy carp_ether_addmulti(struct carp_softc *sc, struct ifreq *ifr) 2297 1.1 liamjfoy { 2298 1.17 dyoung const struct sockaddr *sa = ifreq_getaddr(SIOCADDMULTI, ifr); 2299 1.1 liamjfoy struct ifnet *ifp; 2300 1.1 liamjfoy struct carp_mc_entry *mc; 2301 1.1 liamjfoy u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 2302 1.1 liamjfoy int error; 2303 1.1 liamjfoy 2304 1.1 liamjfoy ifp = sc->sc_carpdev; 2305 1.1 liamjfoy if (ifp == NULL) 2306 1.1 liamjfoy return (EINVAL); 2307 1.1 liamjfoy 2308 1.17 dyoung error = ether_addmulti(sa, &sc->sc_ac); 2309 1.1 liamjfoy if (error != ENETRESET) 2310 1.1 liamjfoy return (error); 2311 1.1 liamjfoy 2312 1.1 liamjfoy /* 2313 1.1 liamjfoy * This is new multicast address. We have to tell parent 2314 1.1 liamjfoy * about it. Also, remember this multicast address so that 2315 1.1 liamjfoy * we can delete them on unconfigure. 2316 1.1 liamjfoy */ 2317 1.28 cegger mc = malloc(sizeof(struct carp_mc_entry), M_DEVBUF, M_NOWAIT); 2318 1.1 liamjfoy if (mc == NULL) { 2319 1.1 liamjfoy error = ENOMEM; 2320 1.1 liamjfoy goto alloc_failed; 2321 1.1 liamjfoy } 2322 1.1 liamjfoy 2323 1.1 liamjfoy /* 2324 1.1 liamjfoy * As ether_addmulti() returns ENETRESET, following two 2325 1.1 liamjfoy * statement shouldn't fail. 2326 1.1 liamjfoy */ 2327 1.17 dyoung (void)ether_multiaddr(sa, addrlo, addrhi); 2328 1.98 yamaguch 2329 1.98 yamaguch ETHER_LOCK(&sc->sc_ac); 2330 1.97 yamaguch mc->mc_enm = ether_lookup_multi(addrlo, addrhi, &sc->sc_ac); 2331 1.98 yamaguch ETHER_UNLOCK(&sc->sc_ac); 2332 1.98 yamaguch 2333 1.17 dyoung memcpy(&mc->mc_addr, sa, sa->sa_len); 2334 1.1 liamjfoy LIST_INSERT_HEAD(&sc->carp_mc_listhead, mc, mc_entries); 2335 1.1 liamjfoy 2336 1.46 dyoung error = if_mcast_op(ifp, SIOCADDMULTI, sa); 2337 1.1 liamjfoy if (error != 0) 2338 1.1 liamjfoy goto ioctl_failed; 2339 1.1 liamjfoy 2340 1.1 liamjfoy return (error); 2341 1.1 liamjfoy 2342 1.1 liamjfoy ioctl_failed: 2343 1.1 liamjfoy LIST_REMOVE(mc, mc_entries); 2344 1.28 cegger free(mc, M_DEVBUF); 2345 1.1 liamjfoy alloc_failed: 2346 1.17 dyoung (void)ether_delmulti(sa, &sc->sc_ac); 2347 1.1 liamjfoy 2348 1.1 liamjfoy return (error); 2349 1.1 liamjfoy } 2350 1.1 liamjfoy 2351 1.58 ozaki static int 2352 1.1 liamjfoy carp_ether_delmulti(struct carp_softc *sc, struct ifreq *ifr) 2353 1.1 liamjfoy { 2354 1.17 dyoung const struct sockaddr *sa = ifreq_getaddr(SIOCDELMULTI, ifr); 2355 1.1 liamjfoy struct ifnet *ifp; 2356 1.1 liamjfoy struct ether_multi *enm; 2357 1.1 liamjfoy struct carp_mc_entry *mc; 2358 1.1 liamjfoy u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN]; 2359 1.1 liamjfoy int error; 2360 1.1 liamjfoy 2361 1.1 liamjfoy ifp = sc->sc_carpdev; 2362 1.1 liamjfoy if (ifp == NULL) 2363 1.1 liamjfoy return (EINVAL); 2364 1.1 liamjfoy 2365 1.1 liamjfoy /* 2366 1.1 liamjfoy * Find a key to lookup carp_mc_entry. We have to do this 2367 1.1 liamjfoy * before calling ether_delmulti for obvious reason. 2368 1.1 liamjfoy */ 2369 1.17 dyoung if ((error = ether_multiaddr(sa, addrlo, addrhi)) != 0) 2370 1.1 liamjfoy return (error); 2371 1.98 yamaguch 2372 1.98 yamaguch ETHER_LOCK(&sc->sc_ac); 2373 1.97 yamaguch enm = ether_lookup_multi(addrlo, addrhi, &sc->sc_ac); 2374 1.98 yamaguch ETHER_UNLOCK(&sc->sc_ac); 2375 1.1 liamjfoy if (enm == NULL) 2376 1.1 liamjfoy return (EINVAL); 2377 1.1 liamjfoy 2378 1.1 liamjfoy LIST_FOREACH(mc, &sc->carp_mc_listhead, mc_entries) 2379 1.1 liamjfoy if (mc->mc_enm == enm) 2380 1.1 liamjfoy break; 2381 1.1 liamjfoy 2382 1.1 liamjfoy /* We won't delete entries we didn't add */ 2383 1.1 liamjfoy if (mc == NULL) 2384 1.1 liamjfoy return (EINVAL); 2385 1.1 liamjfoy 2386 1.17 dyoung error = ether_delmulti(sa, &sc->sc_ac); 2387 1.1 liamjfoy if (error != ENETRESET) 2388 1.1 liamjfoy return (error); 2389 1.1 liamjfoy 2390 1.1 liamjfoy /* We no longer use this multicast address. Tell parent so. */ 2391 1.46 dyoung error = if_mcast_op(ifp, SIOCDELMULTI, sa); 2392 1.1 liamjfoy if (error == 0) { 2393 1.1 liamjfoy /* And forget about this address. */ 2394 1.1 liamjfoy LIST_REMOVE(mc, mc_entries); 2395 1.28 cegger free(mc, M_DEVBUF); 2396 1.1 liamjfoy } else 2397 1.17 dyoung (void)ether_addmulti(sa, &sc->sc_ac); 2398 1.1 liamjfoy return (error); 2399 1.1 liamjfoy } 2400 1.1 liamjfoy 2401 1.1 liamjfoy /* 2402 1.1 liamjfoy * Delete any multicast address we have asked to add from parent 2403 1.1 liamjfoy * interface. Called when the carp is being unconfigured. 2404 1.1 liamjfoy */ 2405 1.58 ozaki static void 2406 1.1 liamjfoy carp_ether_purgemulti(struct carp_softc *sc) 2407 1.1 liamjfoy { 2408 1.1 liamjfoy struct ifnet *ifp = sc->sc_carpdev; /* Parent. */ 2409 1.1 liamjfoy struct carp_mc_entry *mc; 2410 1.1 liamjfoy 2411 1.1 liamjfoy if (ifp == NULL) 2412 1.1 liamjfoy return; 2413 1.1 liamjfoy 2414 1.1 liamjfoy while ((mc = LIST_FIRST(&sc->carp_mc_listhead)) != NULL) { 2415 1.46 dyoung (void)if_mcast_op(ifp, SIOCDELMULTI, sstosa(&mc->mc_addr)); 2416 1.1 liamjfoy LIST_REMOVE(mc, mc_entries); 2417 1.28 cegger free(mc, M_DEVBUF); 2418 1.1 liamjfoy } 2419 1.1 liamjfoy } 2420 1.1 liamjfoy 2421 1.24 thorpej static int 2422 1.24 thorpej sysctl_net_inet_carp_stats(SYSCTLFN_ARGS) 2423 1.24 thorpej { 2424 1.24 thorpej 2425 1.26 thorpej return (NETSTAT_SYSCTL(carpstat_percpu, CARP_NSTATS)); 2426 1.24 thorpej } 2427 1.24 thorpej 2428 1.39 pooka void 2429 1.39 pooka carp_init(void) 2430 1.39 pooka { 2431 1.39 pooka 2432 1.39 pooka sysctl_net_inet_carp_setup(NULL); 2433 1.53 bouyer #ifdef MBUFTRACE 2434 1.53 bouyer MOWNER_ATTACH(&carp_proto_mowner_rx); 2435 1.53 bouyer MOWNER_ATTACH(&carp_proto_mowner_tx); 2436 1.53 bouyer MOWNER_ATTACH(&carp_proto6_mowner_rx); 2437 1.53 bouyer MOWNER_ATTACH(&carp_proto6_mowner_tx); 2438 1.53 bouyer #endif 2439 1.84 ozaki 2440 1.84 ozaki carp_wqinput = wqinput_create("carp", _carp_proto_input); 2441 1.84 ozaki #ifdef INET6 2442 1.84 ozaki carp6_wqinput = wqinput_create("carp6", _carp6_proto_input); 2443 1.84 ozaki #endif 2444 1.39 pooka } 2445 1.39 pooka 2446 1.39 pooka static void 2447 1.39 pooka sysctl_net_inet_carp_setup(struct sysctllog **clog) 2448 1.1 liamjfoy { 2449 1.1 liamjfoy 2450 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2451 1.1 liamjfoy CTLFLAG_PERMANENT, 2452 1.1 liamjfoy CTLTYPE_NODE, "inet", NULL, 2453 1.1 liamjfoy NULL, 0, NULL, 0, 2454 1.1 liamjfoy CTL_NET, PF_INET, CTL_EOL); 2455 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2456 1.1 liamjfoy CTLFLAG_PERMANENT, 2457 1.1 liamjfoy CTLTYPE_NODE, "carp", 2458 1.1 liamjfoy SYSCTL_DESCR("CARP related settings"), 2459 1.1 liamjfoy NULL, 0, NULL, 0, 2460 1.1 liamjfoy CTL_NET, PF_INET, IPPROTO_CARP, CTL_EOL); 2461 1.1 liamjfoy 2462 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2463 1.1 liamjfoy CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 2464 1.1 liamjfoy CTLTYPE_INT, "preempt", 2465 1.1 liamjfoy SYSCTL_DESCR("Enable CARP Preempt"), 2466 1.1 liamjfoy NULL, 0, &carp_opts[CARPCTL_PREEMPT], 0, 2467 1.1 liamjfoy CTL_NET, PF_INET, IPPROTO_CARP, 2468 1.1 liamjfoy CTL_CREATE, CTL_EOL); 2469 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2470 1.1 liamjfoy CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 2471 1.1 liamjfoy CTLTYPE_INT, "arpbalance", 2472 1.1 liamjfoy SYSCTL_DESCR("Enable ARP balancing"), 2473 1.1 liamjfoy NULL, 0, &carp_opts[CARPCTL_ARPBALANCE], 0, 2474 1.1 liamjfoy CTL_NET, PF_INET, IPPROTO_CARP, 2475 1.1 liamjfoy CTL_CREATE, CTL_EOL); 2476 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2477 1.1 liamjfoy CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 2478 1.1 liamjfoy CTLTYPE_INT, "allow", 2479 1.1 liamjfoy SYSCTL_DESCR("Enable CARP"), 2480 1.1 liamjfoy NULL, 0, &carp_opts[CARPCTL_ALLOW], 0, 2481 1.1 liamjfoy CTL_NET, PF_INET, IPPROTO_CARP, 2482 1.1 liamjfoy CTL_CREATE, CTL_EOL); 2483 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2484 1.1 liamjfoy CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 2485 1.1 liamjfoy CTLTYPE_INT, "log", 2486 1.1 liamjfoy SYSCTL_DESCR("CARP logging"), 2487 1.1 liamjfoy NULL, 0, &carp_opts[CARPCTL_LOG], 0, 2488 1.1 liamjfoy CTL_NET, PF_INET, IPPROTO_CARP, 2489 1.1 liamjfoy CTL_CREATE, CTL_EOL); 2490 1.1 liamjfoy sysctl_createv(clog, 0, NULL, NULL, 2491 1.1 liamjfoy CTLFLAG_PERMANENT, 2492 1.1 liamjfoy CTLTYPE_STRUCT, "stats", 2493 1.3 liamjfoy SYSCTL_DESCR("CARP statistics"), 2494 1.24 thorpej sysctl_net_inet_carp_stats, 0, NULL, 0, 2495 1.1 liamjfoy CTL_NET, PF_INET, IPPROTO_CARP, CARPCTL_STATS, 2496 1.1 liamjfoy CTL_EOL); 2497 1.1 liamjfoy } 2498