Projet

Général

Profil

Télécharger (24,9 ko) Statistiques
| Branche: | Révision:

univnautes-tools / patches / stable / 10 / carp_livelock_fixes.diff @ 4ab3b90b

1
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
2
index 2d73edb..456670e 100644
3
--- a/sys/netinet/ip_carp.c
4
+++ b/sys/netinet/ip_carp.c
5
@@ -93,13 +93,8 @@ struct carp_softc {
6
 	struct ifaddr		**sc_ifas;	/* Our ifaddrs. */
7
 	struct sockaddr_dl	sc_addr;	/* Our link level address. */
8
 	struct callout		sc_ad_tmo;	/* Advertising timeout. */
9
-#ifdef INET
10
 	struct callout		sc_md_tmo;	/* Master down timeout. */
11
-#endif
12
-#ifdef INET6
13
-	struct callout 		sc_md6_tmo;	/* XXX: Master down timeout. */
14
-#endif
15
-	struct mtx		sc_mtx;
16
+	struct rwlock		sc_mtx;
17
 
18
 	int			sc_vhid;
19
 	int			sc_advskew;
20
@@ -142,7 +137,7 @@ struct carp_if {
21
 	struct ip6_moptions 	 cif_im6o;
22
 #endif
23
 	struct ifnet	*cif_ifp;
24
-	struct mtx	cif_mtx;
25
+	struct rwlock	 cif_mtx;
26
 };
27
 
28
 #define	CARP_INET	0
29
@@ -240,24 +235,27 @@ VNET_PCPUSTAT_SYSUNINIT(carpstats);
30
 SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats,
31
     carpstats, "CARP statistics (struct carpstats, netinet/ip_carp.h)");
32
 
33
-#define	CARP_LOCK_INIT(sc)	mtx_init(&(sc)->sc_mtx, "carp_softc",   \
34
-	NULL, MTX_DEF)
35
-#define	CARP_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->sc_mtx)
36
-#define	CARP_LOCK_ASSERT(sc)	mtx_assert(&(sc)->sc_mtx, MA_OWNED)
37
-#define	CARP_LOCK(sc)		mtx_lock(&(sc)->sc_mtx)
38
-#define	CARP_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
39
-#define	CIF_LOCK_INIT(cif)	mtx_init(&(cif)->cif_mtx, "carp_if",   \
40
-	NULL, MTX_DEF)
41
-#define	CIF_LOCK_DESTROY(cif)	mtx_destroy(&(cif)->cif_mtx)
42
-#define	CIF_LOCK_ASSERT(cif)	mtx_assert(&(cif)->cif_mtx, MA_OWNED)
43
-#define	CIF_LOCK(cif)		mtx_lock(&(cif)->cif_mtx)
44
-#define	CIF_UNLOCK(cif)		mtx_unlock(&(cif)->cif_mtx)
45
+#define SC2IFP(sc)		((sc)->sc_carpdev)
46
+#define	CARP_LOCK_INIT(sc)	rw_init(&(sc)->sc_mtx, "carp_softc")
47
+#define	CARP_LOCK_DESTROY(sc)	rw_destroy(&(sc)->sc_mtx)
48
+#define	CARP_LOCK_ASSERT(sc)	rw_assert(&(sc)->sc_mtx, MA_OWNED)
49
+#define	CARP_RLOCK(sc)		rw_rlock(&(sc)->sc_mtx)
50
+#define	CARP_WLOCK(sc)		rw_wlock(&(sc)->sc_mtx)
51
+#define	CARP_RUNLOCK(sc)	rw_runlock(&(sc)->sc_mtx)
52
+#define	CARP_WUNLOCK(sc)	rw_wunlock(&(sc)->sc_mtx)
53
+#define	CIF_LOCK_INIT(cif)	rw_init(&(cif)->cif_mtx, "carp_if")
54
+#define	CIF_LOCK_DESTROY(cif)	rw_destroy(&(cif)->cif_mtx)
55
+#define	CIF_LOCK_ASSERT(cif)	rw_assert(&(cif)->cif_mtx, MA_OWNED)
56
+#define	CIF_RLOCK(cif)		rw_rlock(&(cif)->cif_mtx)
57
+#define	CIF_WLOCK(cif)		rw_wlock(&(cif)->cif_mtx)
58
+#define	CIF_RUNLOCK(cif)	rw_runlock(&(cif)->cif_mtx)
59
+#define	CIF_WUNLOCK(cif)	rw_wunlock(&(cif)->cif_mtx)
60
 #define	CIF_FREE(cif)	do {				\
61
 		CIF_LOCK_ASSERT(cif);			\
62
 		if (TAILQ_EMPTY(&(cif)->cif_vrs))	\
63
 			carp_free_if(cif);		\
64
 		else					\
65
-			CIF_UNLOCK(cif);		\
66
+			CIF_WUNLOCK(cif);		\
67
 } while (0)
68
 
69
 #define	CARP_LOG(...)	do {				\
70
@@ -300,11 +298,11 @@ static struct carp_if
71
 static void	carp_free_if(struct carp_if *);
72
 static void	carp_set_state(struct carp_softc *, int);
73
 static void	carp_sc_state(struct carp_softc *);
74
-static void	carp_setrun(struct carp_softc *, sa_family_t);
75
+static void	carp_setrun(struct carp_softc *);
76
 static void	carp_master_down(void *);
77
 static void	carp_master_down_locked(struct carp_softc *);
78
 static void	carp_send_ad(void *);
79
-static void	carp_send_ad_locked(struct carp_softc *);
80
+static void	carp_send_ad_locked(struct carp_softc *, int);
81
 static void	carp_addroute(struct carp_softc *);
82
 static void	carp_ifa_addroute(struct ifaddr *);
83
 static void	carp_delroute(struct carp_softc *);
84
@@ -580,6 +578,15 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
85
 	struct carp_softc *sc;
86
 	struct timeval sc_tv, ch_tv;
87
 
88
+	/* verify the CARP version. */
89
+	if (ch->carp_version != CARP_VERSION) {
90
+		CARPSTATS_INC(carps_badver);
91
+		CARP_DEBUG("%s: invalid version %d\n", ifp->if_xname,
92
+		    ch->carp_version);
93
+		m_freem(m);
94
+		return;
95
+	}
96
+
97
 	/* verify that the VHID is valid on the receiving interface */
98
 	IF_ADDR_RLOCK(ifp);
99
 	IFNET_FOREACH_IFA(ifp, ifa)
100
@@ -596,18 +603,8 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
101
 		return;
102
 	}
103
 
104
-	/* verify the CARP version. */
105
-	if (ch->carp_version != CARP_VERSION) {
106
-		CARPSTATS_INC(carps_badver);
107
-		CARP_DEBUG("%s: invalid version %d\n", ifp->if_xname,
108
-		    ch->carp_version);
109
-		ifa_free(ifa);
110
-		m_freem(m);
111
-		return;
112
-	}
113
-
114
 	sc = ifa->ifa_carp;
115
-	CARP_LOCK(sc);
116
+	CARP_WLOCK(sc);
117
 	ifa_free(ifa);
118
 
119
 	if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
120
@@ -620,14 +617,14 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
121
 	if (!bcmp(&sc->sc_counter, ch->carp_counter,
122
             sizeof(ch->carp_counter))) {
123
                 /* Do not log duplicates from non simplex interfaces */
124
-                if (sc->sc_carpdev->if_flags & IFF_SIMPLEX) {
125
+                if (ifp->if_flags & IFF_SIMPLEX) {
126
                         CARPSTATS_INC(carps_badauth);
127
                         ifp->if_ierrors++;
128
-                        CARP_UNLOCK(sc);
129
+                        CARP_WUNLOCK(sc);
130
                         CARP_LOG("%s, replay or network loop detected.\n",
131
 				ifp->if_xname);
132
                 } else
133
-                        CARP_UNLOCK(sc);
134
+                        CARP_WUNLOCK(sc);
135
                 m_freem(m);
136
                 return;
137
         }
138
@@ -651,9 +648,9 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
139
 			CARP_LOG("VHID %u@%s: MASTER -> BACKUP "
140
 			    "(more frequent advertisement received)\n",
141
 			    sc->sc_vhid,
142
-			    sc->sc_carpdev->if_xname);
143
+			    SC2IFP(sc)->if_xname);
144
 			carp_set_state(sc, BACKUP);
145
-			carp_setrun(sc, 0);
146
+			carp_setrun(sc);
147
 			carp_delroute(sc);
148
 		}
149
 		break;
150
@@ -666,7 +663,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
151
 			CARP_LOG("VHID %u@%s: BACKUP -> MASTER "
152
 			    "(preempting a slower master)\n",
153
 			    sc->sc_vhid,
154
-			    sc->sc_carpdev->if_xname);
155
+			    SC2IFP(sc)->if_xname);
156
 			carp_master_down_locked(sc);
157
 			break;
158
 		}
159
@@ -681,7 +678,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
160
 			CARP_LOG("VHID %u@%s: BACKUP -> MASTER "
161
 			    "(master timed out)\n",
162
 			    sc->sc_vhid,
163
-			    sc->sc_carpdev->if_xname);
164
+			    SC2IFP(sc)->if_xname);
165
 			carp_master_down_locked(sc);
166
 			break;
167
 		}
168
@@ -690,12 +687,12 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
169
 		 * Otherwise, we reset the counter and wait for the next
170
 		 * advertisement.
171
 		 */
172
-		carp_setrun(sc, af);
173
+		carp_setrun(sc);
174
 		break;
175
 	}
176
 
177
 out:
178
-	CARP_UNLOCK(sc);
179
+	CARP_WUNLOCK(sc);
180
 	m_freem(m);
181
 }
182
 
183
@@ -716,6 +713,7 @@ carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch)
184
 
185
 	carp_hmac_generate(sc, ch->carp_counter, ch->carp_md);
186
 
187
+	/* XXX: Why this is handled so badly with new design? */
188
 	/* Tag packet for carp_output */
189
 	if ((mtag = m_tag_get(PACKET_TAG_CARP, sizeof(struct carp_softc *),
190
 	    M_NOWAIT)) == NULL) {
191
@@ -739,14 +737,19 @@ carp_send_ad_all(void *ctx __unused, int pending __unused)
192
 	struct carp_softc *sc;
193
 
194
 	mtx_lock(&carp_mtx);
195
-	LIST_FOREACH(sc, &carp_list, sc_next)
196
-		if (sc->sc_state == MASTER) {
197
-			CARP_LOCK(sc);
198
-			CURVNET_SET(sc->sc_carpdev->if_vnet);
199
-			carp_send_ad_locked(sc);
200
+	LIST_FOREACH(sc, &carp_list, sc_next) {
201
+		if (sc->sc_carpdev == NULL)
202
+			continue;
203
+		CARP_RLOCK(sc);
204
+		if ((SC2IFP(sc)->if_flags & IFF_UP) &&
205
+		    (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING) &&
206
+		    sc->sc_state == MASTER) {
207
+			CURVNET_SET(SC2IFP(sc)->if_vnet);
208
+			carp_send_ad_locked(sc, 0);
209
 			CURVNET_RESTORE();
210
-			CARP_UNLOCK(sc);
211
 		}
212
+		CARP_RUNLOCK(sc);
213
+	}
214
 	mtx_unlock(&carp_mtx);
215
 }
216
 
217
@@ -756,29 +759,43 @@ carp_send_ad(void *v)
218
 {
219
 	struct carp_softc *sc = v;
220
 
221
-	CARP_LOCK_ASSERT(sc);
222
-	CURVNET_SET(sc->sc_carpdev->if_vnet);
223
-	carp_send_ad_locked(sc);
224
-	CURVNET_RESTORE();
225
-	CARP_UNLOCK(sc);
226
+	CARP_LOCK_ASSERT(sc);
227
+
228
+	if (sc->sc_carpdev != NULL)
229
+		CURVNET_SET(SC2IFP(sc)->if_vnet);
230
+	carp_send_ad_locked(sc, 0);
231
+	if (sc->sc_carpdev != NULL)
232
+		CURVNET_RESTORE();
233
+
234
+	CARP_RUNLOCK(sc);
235
 }
236
 
237
 static void
238
-carp_send_ad_locked(struct carp_softc *sc)
239
+carp_send_ad_locked(struct carp_softc *sc, int wlocked)
240
 {
241
 	struct carp_header ch;
242
 	struct timeval tv;
243
-	struct sockaddr sa;
244
 	struct ifaddr *ifa;
245
 	struct carp_header *ch_ptr;
246
 	struct mbuf *m;
247
 	int len, advskew;
248
 
249
-	CARP_LOCK_ASSERT(sc);
250
+	if (sc->sc_carpdev)
251
+		CARP_LOCK_ASSERT(sc);
252
 
253
-	advskew = DEMOTE_ADVSKEW(sc);
254
-	tv.tv_sec = sc->sc_advbase;
255
-	tv.tv_usec = advskew * 1000000 / 256;
256
+	 /* bow out if we've lost our UPness or RUNNINGuiness */
257
+        if (!((SC2IFP(sc)->if_flags & IFF_UP) &&
258
+            (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING))) {
259
+                sc->sc_advbase = 255;
260
+                sc->sc_advskew = 255;
261
+	} else {
262
+		advskew = DEMOTE_ADVSKEW(sc);
263
+		tv.tv_sec = sc->sc_advbase;
264
+		tv.tv_usec = advskew * 1000000 / 256;
265
+	}
266
+
267
+	if (!carp_allow)
268
+		goto resched;
269
 
270
 	ch.carp_version = CARP_VERSION;
271
 	ch.carp_type = CARP_ADVERTISEMENT;
272
@@ -817,9 +834,9 @@ carp_send_ad_locked(struct carp_softc *sc)
273
 		ip->ip_p = IPPROTO_CARP;
274
 		ip->ip_sum = 0;
275
 
276
-		bzero(&sa, sizeof(sa));
277
-		sa.sa_family = AF_INET;
278
-		ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
279
+		CARP_FOREACH_IFA(sc, ifa)
280
+			if (ifa->ifa_addr->sa_family == AF_INET)
281
+				break;
282
 		if (ifa != NULL) {
283
 			ip->ip_src.s_addr =
284
 			    ifatoia(ifa)->ia_addr.sin_addr.s_addr;
285
@@ -839,24 +856,41 @@ carp_send_ad_locked(struct carp_softc *sc)
286
 
287
 		CARPSTATS_INC(carps_opackets);
288
 
289
+		if (wlocked)
290
+			CARP_WUNLOCK(sc);
291
+		else
292
+			CARP_RUNLOCK(sc);
293
 		if (ip_output(m, NULL, NULL, IP_RAWOUTPUT,
294
-		    &sc->sc_carpdev->if_carp->cif_imo, NULL)) {
295
-			if (sc->sc_sendad_errors < INT_MAX)
296
-				sc->sc_sendad_errors++;
297
-			if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS)
298
-				carp_demote_adj(V_carp_senderr_adj,
299
-				    "send error");
300
-			sc->sc_sendad_success = 0;
301
+		    &SC2IFP(sc)->if_carp->cif_imo, NULL)) {
302
+			if (sc && sc->sc_carpdev) {
303
+				if (wlocked)
304
+					CARP_WLOCK(sc);
305
+				else
306
+					CARP_RLOCK(sc);
307
+
308
+				if (sc->sc_sendad_errors < INT_MAX)
309
+					sc->sc_sendad_errors++;
310
+				if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS)
311
+					carp_demote_adj(carp_senderr_adj, "send error");
312
+				sc->sc_sendad_success = 0;
313
+			}
314
 		} else {
315
-			if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
316
-				if (++sc->sc_sendad_success >=
317
-				    CARP_SENDAD_MIN_SUCCESS) {
318
-					carp_demote_adj(-V_carp_senderr_adj,
319
-					    "send ok");
320
+			if (sc && sc->sc_carpdev) {
321
+				if (wlocked)
322
+					CARP_WLOCK(sc);
323
+				else
324
+					CARP_RLOCK(sc);
325
+
326
+				if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
327
+					if (++sc->sc_sendad_success >=
328
+					    CARP_SENDAD_MIN_SUCCESS) {
329
+						carp_demote_adj(-carp_senderr_adj,
330
+						    "send ok");
331
+						sc->sc_sendad_errors = 0;
332
+					}
333
+				} else
334
 					sc->sc_sendad_errors = 0;
335
-				}
336
-			} else
337
-				sc->sc_sendad_errors = 0;
338
+			}
339
 		}
340
 	}
341
 #endif /* INET */
342
@@ -880,15 +914,13 @@ carp_send_ad_locked(struct carp_softc *sc)
343
 		ip6->ip6_vfc |= IPV6_VERSION;
344
 		ip6->ip6_hlim = CARP_DFLTTL;
345
 		ip6->ip6_nxt = IPPROTO_CARP;
346
-		bzero(&sa, sizeof(sa));
347
 
348
-		/* set the source address */
349
-		sa.sa_family = AF_INET6;
350
-		ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
351
+		CARP_FOREACH_IFA(sc, ifa)
352
+			if (ifa->ifa_addr->sa_family == AF_INET6)
353
+				break;
354
 		if (ifa != NULL) {
355
 			bcopy(IFA_IN6(ifa), &ip6->ip6_src,
356
 			    sizeof(struct in6_addr));
357
-			ifa_free(ifa);
358
 		} else
359
 			/* This should never happen with IPv6. */
360
 			bzero(&ip6->ip6_src, sizeof(struct in6_addr));
361
@@ -913,30 +945,47 @@ carp_send_ad_locked(struct carp_softc *sc)
362
 
363
 		CARPSTATS_INC(carps_opackets6);
364
 
365
+		if (wlocked)
366
+			CARP_WUNLOCK(sc);
367
+		else
368
+			CARP_RUNLOCK(sc);
369
 		if (ip6_output(m, NULL, NULL, 0,
370
 		    &sc->sc_carpdev->if_carp->cif_im6o, NULL, NULL)) {
371
-			if (sc->sc_sendad_errors < INT_MAX)
372
-				sc->sc_sendad_errors++;
373
-			if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS)
374
-				carp_demote_adj(V_carp_senderr_adj,
375
-				    "send6 error");
376
-			sc->sc_sendad_success = 0;
377
+			if (sc && sc->sc_carpdev) {
378
+				if (wlocked)
379
+					CARP_WLOCK(sc);
380
+				else
381
+					CARP_RLOCK(sc);
382
+				if (sc->sc_sendad_errors < INT_MAX)
383
+					sc->sc_sendad_errors++;
384
+				if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS)
385
+					carp_demote_adj(carp_senderr_adj,
386
+					    "send6 error");
387
+				sc->sc_sendad_success = 0;
388
+			}
389
 		} else {
390
-			if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
391
-				if (++sc->sc_sendad_success >=
392
-				    CARP_SENDAD_MIN_SUCCESS) {
393
-					carp_demote_adj(-V_carp_senderr_adj,
394
-					    "send6 ok");
395
+			if (sc && sc->sc_carpdev) {
396
+				if (wlocked)
397
+					CARP_WLOCK(sc);
398
+				else
399
+					CARP_RLOCK(sc);
400
+				if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
401
+					if (++sc->sc_sendad_success >=
402
+					    CARP_SENDAD_MIN_SUCCESS) {
403
+						carp_demote_adj(-carp_senderr_adj,
404
+						    "send6 ok");
405
+						sc->sc_sendad_errors = 0;
406
+					}
407
+				} else
408
 					sc->sc_sendad_errors = 0;
409
-				}
410
-			} else
411
-				sc->sc_sendad_errors = 0;
412
+			}
413
 		}
414
 	}
415
 #endif /* INET6 */
416
 
417
 resched:
418
-	callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), carp_send_ad, sc);
419
+	if (sc->sc_advbase != 255 || sc->sc_advskew != 255)
420
+		callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), carp_send_ad, sc);
421
 }
422
 
423
 static void
424
@@ -1009,7 +1058,7 @@ carp_master(struct ifaddr *ifa)
425
 	return (sc->sc_state == MASTER);
426
 }
427
 
428
-#ifdef INET
429
+#if defined(INET) || defined(INET6)
430
 /*
431
  * Broadcast a gratuitous ARP request containing
432
  * the virtual router MAC address for each IP address
433
@@ -1019,12 +1068,29 @@ static void
434
 carp_send_arp(struct carp_softc *sc)
435
 {
436
 	struct ifaddr *ifa;
437
+#ifdef INET6
438
+	static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
439
+	struct in6_addr *in6;
440
+#endif
441
 
442
-	CARP_FOREACH_IFA(sc, ifa)
443
+	CARP_FOREACH_IFA(sc, ifa) {
444
+#ifdef INET
445
 		if (ifa->ifa_addr->sa_family == AF_INET)
446
 			arp_ifinit2(sc->sc_carpdev, ifa, LLADDR(&sc->sc_addr));
447
+#endif
448
+#ifdef INET6
449
+		else if (ifa->ifa_addr->sa_family == AF_INET6) {
450
+			in6 = IFA_IN6(ifa);
451
+			nd6_na_output(sc->sc_carpdev, &mcast, in6,
452
+			    ND_NA_FLAG_OVERRIDE, 1, NULL);
453
+			DELAY(1000);    /* XXX */
454
+		}
455
+#endif
456
+	}
457
 }
458
+#endif
459
 
460
+#ifdef INET
461
 int
462
 carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr)
463
 {
464
@@ -1040,24 +1106,6 @@ carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr)
465
 #endif
466
 
467
 #ifdef INET6
468
-static void
469
-carp_send_na(struct carp_softc *sc)
470
-{
471
-	static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
472
-	struct ifaddr *ifa;
473
-	struct in6_addr *in6;
474
-
475
-	CARP_FOREACH_IFA(sc, ifa) {
476
-		if (ifa->ifa_addr->sa_family != AF_INET6)
477
-			continue;
478
-
479
-		in6 = IFA_IN6(ifa);
480
-		nd6_na_output(sc->sc_carpdev, &mcast, in6,
481
-		    ND_NA_FLAG_OVERRIDE, 1, NULL);
482
-		DELAY(1000);	/* XXX */
483
-	}
484
-}
485
-
486
 /*
487
  * Returns ifa in case it's a carp address and it is MASTER, or if the address
488
  * matches and is not a carp address.  Returns NULL otherwise.
489
@@ -1125,18 +1173,18 @@ carp_forus(struct ifnet *ifp, u_char *dhost)
490
 	if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1)
491
 		return (0);
492
 
493
-	CIF_LOCK(ifp->if_carp);
494
+	CIF_RLOCK(ifp->if_carp);
495
 	IFNET_FOREACH_CARP(ifp, sc) {
496
-		CARP_LOCK(sc);
497
+		CARP_RLOCK(sc);
498
 		if (sc->sc_state == MASTER && !bcmp(dhost, LLADDR(&sc->sc_addr),
499
 		    ETHER_ADDR_LEN)) {
500
-			CARP_UNLOCK(sc);
501
-			CIF_UNLOCK(ifp->if_carp);
502
+			CARP_RUNLOCK(sc);
503
+			CIF_RUNLOCK(ifp->if_carp);
504
 			return (1);
505
 		}
506
-		CARP_UNLOCK(sc);
507
+		CARP_RUNLOCK(sc);
508
 	}
509
-	CIF_UNLOCK(ifp->if_carp);
510
+	CIF_RUNLOCK(ifp->if_carp);
511
 
512
 	return (0);
513
 }
514
@@ -1149,16 +1197,18 @@ carp_master_down(void *v)
515
 
516
 	CARP_LOCK_ASSERT(sc);
517
 
518
-	CURVNET_SET(sc->sc_carpdev->if_vnet);
519
+	if (sc->sc_carpdev)
520
+		CURVNET_SET(SC2IFP(sc)->if_vnet);
521
 	if (sc->sc_state == BACKUP) {
522
 		CARP_LOG("VHID %u@%s: BACKUP -> MASTER (master down)\n",
523
 		    sc->sc_vhid,
524
 		    sc->sc_carpdev->if_xname);
525
 		carp_master_down_locked(sc);
526
 	}
527
-	CURVNET_RESTORE();
528
+	if (sc->sc_carpdev)
529
+		CURVNET_RESTORE();
530
 
531
-	CARP_UNLOCK(sc);
532
+	CARP_RUNLOCK(sc);
533
 }
534
 
535
 static void
536
@@ -1170,14 +1220,11 @@ carp_master_down_locked(struct carp_softc *sc)
537
 	switch (sc->sc_state) {
538
 	case BACKUP:
539
 		carp_set_state(sc, MASTER);
540
-		carp_send_ad_locked(sc);
541
-#ifdef INET
542
+		carp_send_ad_locked(sc, 0);
543
+#if defined(INET) || defined(INET6)
544
 		carp_send_arp(sc);
545
 #endif
546
-#ifdef INET6
547
-		carp_send_na(sc);
548
-#endif
549
-		carp_setrun(sc, 0);
550
+		carp_setrun(sc);
551
 		carp_addroute(sc);
552
 		break;
553
 	case INIT:
554
@@ -1197,14 +1244,14 @@ carp_master_down_locked(struct carp_softc *sc)
555
  * for v4 or v6. If it's set to zero, reset the ones which are already pending.
556
  */
557
 static void
558
-carp_setrun(struct carp_softc *sc, sa_family_t af)
559
+carp_setrun(struct carp_softc *sc)
560
 {
561
 	struct timeval tv;
562
 
563
 	CARP_LOCK_ASSERT(sc);
564
 
565
-	if ((sc->sc_carpdev->if_flags & IFF_UP) == 0 ||
566
-	    sc->sc_carpdev->if_link_state != LINK_STATE_UP ||
567
+	if ((SC2IFP(sc)->if_flags & IFF_UP) == 0 ||
568
+	    SC2IFP(sc)->if_link_state != LINK_STATE_UP ||
569
 	    (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0))
570
 		return;
571
 
572
@@ -1214,38 +1261,14 @@ carp_setrun(struct carp_softc *sc, sa_family_t af)
573
 		    sc->sc_vhid,
574
 		    sc->sc_carpdev->if_xname);
575
 		carp_set_state(sc, BACKUP);
576
-		carp_setrun(sc, 0);
577
+		carp_setrun(sc);
578
 		break;
579
 	case BACKUP:
580
 		callout_stop(&sc->sc_ad_tmo);
581
 		tv.tv_sec = 3 * sc->sc_advbase;
582
 		tv.tv_usec = sc->sc_advskew * 1000000 / 256;
583
-		switch (af) {
584
-#ifdef INET
585
-		case AF_INET:
586
-			callout_reset(&sc->sc_md_tmo, tvtohz(&tv),
587
-			    carp_master_down, sc);
588
-			break;
589
-#endif
590
-#ifdef INET6
591
-		case AF_INET6:
592
-			callout_reset(&sc->sc_md6_tmo, tvtohz(&tv),
593
-			    carp_master_down, sc);
594
-			break;
595
-#endif
596
-		default:
597
-#ifdef INET
598
-			if (sc->sc_naddrs)
599
-				callout_reset(&sc->sc_md_tmo, tvtohz(&tv),
600
-				    carp_master_down, sc);
601
-#endif
602
-#ifdef INET6
603
-			if (sc->sc_naddrs6)
604
-				callout_reset(&sc->sc_md6_tmo, tvtohz(&tv),
605
-				    carp_master_down, sc);
606
-#endif
607
-			break;
608
-		}
609
+		callout_reset(&sc->sc_md_tmo, tvtohz(&tv),
610
+		    carp_master_down, sc);
611
 		break;
612
 	case MASTER:
613
 		tv.tv_sec = sc->sc_advbase;
614
@@ -1503,17 +1526,12 @@ carp_alloc(struct ifnet *ifp)
615
 	sc->sc_carpdev = ifp;
616
 
617
 	CARP_LOCK_INIT(sc);
618
-#ifdef INET
619
-	callout_init_mtx(&sc->sc_md_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
620
-#endif
621
-#ifdef INET6
622
-	callout_init_mtx(&sc->sc_md6_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
623
-#endif
624
-	callout_init_mtx(&sc->sc_ad_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
625
+	callout_init_rw(&sc->sc_md_tmo, &sc->sc_mtx, CALLOUT_SHAREDLOCK | CALLOUT_RETURNUNLOCKED);
626
+	callout_init_rw(&sc->sc_ad_tmo, &sc->sc_mtx, CALLOUT_SHAREDLOCK | CALLOUT_RETURNUNLOCKED);
627
 
628
-	CIF_LOCK(cif);
629
+	CIF_WLOCK(cif);
630
 	TAILQ_INSERT_TAIL(&cif->cif_vrs, sc, sc_list);
631
-	CIF_UNLOCK(cif);
632
+	CIF_WUNLOCK(cif);
633
 
634
 	mtx_lock(&carp_mtx);
635
 	LIST_INSERT_HEAD(&carp_list, sc, sc_next);
636
@@ -1554,16 +1572,11 @@ carp_destroy(struct carp_softc *sc)
637
 	LIST_REMOVE(sc, sc_next);
638
 	mtx_unlock(&carp_mtx);
639
 
640
-	CARP_LOCK(sc);
641
+	CARP_WLOCK(sc);
642
 	if (sc->sc_suppress)
643
 		carp_demote_adj(-V_carp_ifdown_adj, "vhid removed");
644
 	callout_drain(&sc->sc_ad_tmo);
645
-#ifdef INET
646
 	callout_drain(&sc->sc_md_tmo);
647
-#endif
648
-#ifdef INET6
649
-	callout_drain(&sc->sc_md6_tmo);
650
-#endif
651
 	CARP_LOCK_DESTROY(sc);
652
 
653
 	free(sc->sc_ifas, M_CARP);
654
@@ -1622,7 +1635,7 @@ static void
655
 carp_carprcp(struct carpreq *carpr, struct carp_softc *sc, int priv)
656
 {
657
 
658
-	CARP_LOCK(sc);
659
+	CARP_RLOCK(sc);
660
 	carpr->carpr_state = sc->sc_state;
661
 	carpr->carpr_vhid = sc->sc_vhid;
662
 	carpr->carpr_advbase = sc->sc_advbase;
663
@@ -1631,7 +1644,7 @@ carp_carprcp(struct carpreq *carpr, struct carp_softc *sc, int priv)
664
 		bcopy(sc->sc_key, carpr->carpr_key, sizeof(carpr->carpr_key));
665
 	else
666
 		bzero(carpr->carpr_key, sizeof(carpr->carpr_key));
667
-	CARP_UNLOCK(sc);
668
+	CARP_RUNLOCK(sc);
669
 }
670
 
671
 int
672
@@ -1677,11 +1690,11 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
673
 		}
674
 
675
 		if (ifp->if_carp) {
676
-			CIF_LOCK(ifp->if_carp);
677
+			CIF_RLOCK(ifp->if_carp);
678
 			IFNET_FOREACH_CARP(ifp, sc)
679
 				if (sc->sc_vhid == carpr.carpr_vhid)
680
 					break;
681
-			CIF_UNLOCK(ifp->if_carp);
682
+			CIF_RUNLOCK(ifp->if_carp);
683
 		}
684
 		if (sc == NULL) {
685
 			sc = carp_alloc(ifp);
686
@@ -1690,7 +1703,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
687
 				break;
688
 			}
689
 
690
-			CARP_LOCK(sc);
691
+			CARP_WLOCK(sc);
692
 			sc->sc_vhid = carpr.carpr_vhid;
693
 			LLADDR(&sc->sc_addr)[0] = 0;
694
 			LLADDR(&sc->sc_addr)[1] = 0;
695
@@ -1699,7 +1712,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
696
 			LLADDR(&sc->sc_addr)[4] = 1;
697
 			LLADDR(&sc->sc_addr)[5] = sc->sc_vhid;
698
 		} else
699
-			CARP_LOCK(sc);
700
+			CARP_WLOCK(sc);
701
 		locked = 1;
702
 		if (carpr.carpr_advbase > 0) {
703
 			if (carpr.carpr_advbase > 255 ||
704
@@ -1726,7 +1739,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
705
 			case BACKUP:
706
 				callout_stop(&sc->sc_ad_tmo);
707
 				carp_set_state(sc, BACKUP);
708
-				carp_setrun(sc, 0);
709
+				carp_setrun(sc);
710
 				carp_delroute(sc);
711
 				break;
712
 			case MASTER:
713
@@ -1757,11 +1770,11 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
714
 
715
 		priveleged = (priv_check(td, PRIV_NETINET_CARP) == 0);
716
 		if (carpr.carpr_vhid != 0) {
717
-			CIF_LOCK(ifp->if_carp);
718
+			CIF_RLOCK(ifp->if_carp);
719
 			IFNET_FOREACH_CARP(ifp, sc)
720
 				if (sc->sc_vhid == carpr.carpr_vhid)
721
 					break;
722
-			CIF_UNLOCK(ifp->if_carp);
723
+			CIF_RUNLOCK(ifp->if_carp);
724
 			if (sc == NULL) {
725
 				error = ENOENT;
726
 				break;
727
@@ -1772,12 +1785,12 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
728
 			int i, count;
729
 
730
 			count = 0;
731
-			CIF_LOCK(ifp->if_carp);
732
+			CIF_RLOCK(ifp->if_carp);
733
 			IFNET_FOREACH_CARP(ifp, sc)
734
 				count++;
735
 
736
 			if (count > carpr.carpr_count) {
737
-				CIF_UNLOCK(ifp->if_carp);
738
+				CIF_RUNLOCK(ifp->if_carp);
739
 				error = EMSGSIZE;
740
 				break;
741
 			}
742
@@ -1789,12 +1802,12 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
743
 				error = copyout(&carpr, ifr->ifr_data +
744
 				    (i * sizeof(carpr)), sizeof(carpr));
745
 				if (error) {
746
-					CIF_UNLOCK(ifp->if_carp);
747
+					CIF_RUNLOCK(ifp->if_carp);
748
 					break;
749
 				}
750
 				i++;
751
 			}
752
-			CIF_UNLOCK(ifp->if_carp);
753
+			CIF_RUNLOCK(ifp->if_carp);
754
 		}
755
 		break;
756
 	    }
757
@@ -1804,7 +1817,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
758
 
759
 out:
760
 	if (locked)
761
-		CARP_UNLOCK(sc);
762
+		CARP_WUNLOCK(sc);
763
 	if_rele(ifp);
764
 
765
 	return (error);
766
@@ -1843,12 +1856,12 @@ carp_attach(struct ifaddr *ifa, int vhid)
767
 		return (EPROTOTYPE);
768
 	}
769
 
770
-	CIF_LOCK(cif);
771
+	CIF_WLOCK(cif);
772
 	IFNET_FOREACH_CARP(ifp, sc)
773
 		if (sc->sc_vhid == vhid)
774
 			break;
775
 	if (sc == NULL) {
776
-		CIF_UNLOCK(cif);
777
+		CIF_WUNLOCK(cif);
778
 		return (ENOENT);
779
 	}
780
 
781
@@ -1856,7 +1869,7 @@ carp_attach(struct ifaddr *ifa, int vhid)
782
 		if (ifa->ifa_carp->sc_vhid != vhid)
783
 			carp_detach_locked(ifa);
784
 		else {
785
-			CIF_UNLOCK(cif);
786
+			CIF_WUNLOCK(cif);
787
 			return (0);
788
 		}
789
 	}
790
@@ -1867,13 +1880,13 @@ carp_attach(struct ifaddr *ifa, int vhid)
791
 		return (error);
792
 	}
793
 
794
-	CARP_LOCK(sc);
795
+	CARP_WLOCK(sc);
796
 	index = sc->sc_naddrs + sc->sc_naddrs6 + 1;
797
 	if (index > sc->sc_ifasiz / sizeof(struct ifaddr *))
798
 		if ((error = carp_grow_ifas(sc)) != 0) {
799
 			carp_multicast_cleanup(cif,
800
 			    ifa->ifa_addr->sa_family);
801
-			CARP_UNLOCK(sc);
802
+			CARP_WUNLOCK(sc);
803
 			CIF_FREE(cif);
804
 			return (error);
805
 		}
806
@@ -1900,8 +1913,8 @@ carp_attach(struct ifaddr *ifa, int vhid)
807
 	carp_hmac_prepare(sc);
808
 	carp_sc_state(sc);
809
 
810
-	CARP_UNLOCK(sc);
811
-	CIF_UNLOCK(cif);
812
+	CARP_WUNLOCK(sc);
813
+	CIF_WUNLOCK(cif);
814
 
815
 	return (0);
816
 }
817
@@ -1912,7 +1925,7 @@ carp_detach(struct ifaddr *ifa)
818
 	struct ifnet *ifp = ifa->ifa_ifp;
819
 	struct carp_if *cif = ifp->if_carp;
820
 
821
-	CIF_LOCK(cif);
822
+	CIF_WLOCK(cif);
823
 	carp_detach_locked(ifa);
824
 	CIF_FREE(cif);
825
 }
826
@@ -1928,7 +1941,7 @@ carp_detach_locked(struct ifaddr *ifa)
827
 	KASSERT(sc != NULL, ("%s: %p not attached", __func__, ifa));
828
 
829
 	CIF_LOCK_ASSERT(cif);
830
-	CARP_LOCK(sc);
831
+	CARP_WLOCK(sc);
832
 
833
 	/* Shift array. */
834
 	index = sc->sc_naddrs + sc->sc_naddrs6;
835
@@ -1965,10 +1978,10 @@ carp_detach_locked(struct ifaddr *ifa)
836
 	carp_sc_state(sc);
837
 
838
 	if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) {
839
-		CARP_UNLOCK(sc);
840
+		CARP_WUNLOCK(sc);
841
 		carp_destroy(sc);
842
 	} else
843
-		CARP_UNLOCK(sc);
844
+		CARP_WUNLOCK(sc);
845
 }
846
 
847
 static void
848
@@ -1981,11 +1994,13 @@ carp_set_state(struct carp_softc *sc, int state)
849
 		const char *carp_states[] = { CARP_STATES };
850
 		char subsys[IFNAMSIZ+5];
851
 
852
-		sc->sc_state = state;
853
+		atomic_set_int(&sc->sc_state, state);
854
 
855
-		snprintf(subsys, IFNAMSIZ+5, "%u@%s", sc->sc_vhid,
856
-		    sc->sc_carpdev->if_xname);
857
-		devctl_notify("CARP", subsys, carp_states[state], NULL);
858
+		if (sc->sc_carpdev) {
859
+			snprintf(subsys, IFNAMSIZ+5, "%u@%s", sc->sc_vhid,
860
+			    SC2IFP(sc)->if_xname);
861
+			devctl_notify("CARP", subsys, carp_states[state], NULL);
862
+		}
863
 	}
864
 }
865
 
866
@@ -1994,13 +2009,13 @@ carp_linkstate(struct ifnet *ifp)
867
 {
868
 	struct carp_softc *sc;
869
 
870
-	CIF_LOCK(ifp->if_carp);
871
+	CIF_RLOCK(ifp->if_carp);
872
 	IFNET_FOREACH_CARP(ifp, sc) {
873
-		CARP_LOCK(sc);
874
+		CARP_WLOCK(sc);
875
 		carp_sc_state(sc);
876
-		CARP_UNLOCK(sc);
877
+		CARP_WUNLOCK(sc);
878
 	}
879
-	CIF_UNLOCK(ifp->if_carp);
880
+	CIF_RUNLOCK(ifp->if_carp);
881
 }
882
 
883
 static void
884
@@ -2012,20 +2027,15 @@ carp_sc_state(struct carp_softc *sc)
885
 	if (sc->sc_carpdev->if_link_state != LINK_STATE_UP ||
886
 	    !(sc->sc_carpdev->if_flags & IFF_UP)) {
887
 		callout_stop(&sc->sc_ad_tmo);
888
-#ifdef INET
889
 		callout_stop(&sc->sc_md_tmo);
890
-#endif
891
-#ifdef INET6
892
-		callout_stop(&sc->sc_md6_tmo);
893
-#endif
894
 		carp_set_state(sc, INIT);
895
-		carp_setrun(sc, 0);
896
+		carp_setrun(sc);
897
 		if (!sc->sc_suppress)
898
 			carp_demote_adj(V_carp_ifdown_adj, "interface down");
899
 		sc->sc_suppress = 1;
900
 	} else {
901
 		carp_set_state(sc, INIT);
902
-		carp_setrun(sc, 0);
903
+		carp_setrun(sc);
904
 		if (sc->sc_suppress)
905
 			carp_demote_adj(-V_carp_ifdown_adj, "interface up");
906
 		sc->sc_suppress = 0;
(11-11/67)