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;
|