1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * RDC interface health monitoring code.
28 */
29
30 #include <sys/types.h>
31 #include <sys/ksynch.h>
32 #include <sys/errno.h>
33 #include <sys/debug.h>
34 #include <sys/cmn_err.h>
35 #include <sys/kmem.h>
36
37 #include <sys/errno.h>
38
39 #ifdef _SunOS_2_6
40 /*
41 * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we
42 * define enum_t here as it is all we need from rpc/types.h
43 * anyway and make it look like we included it. Yuck.
44 */
45 #define _RPC_TYPES_H
46 typedef int enum_t;
47 #else
48 #ifndef DS_DDICT
49 #include <rpc/types.h>
50 #endif
51 #endif /* _SunOS_2_6 */
52
53 #include <sys/ddi.h>
54 #include <sys/nsc_thread.h>
55 #ifdef DS_DDICT
56 #include <sys/nsctl/contract.h>
57 #endif
58 #include <sys/nsctl/nsctl.h>
59
60 #include <sys/unistat/spcs_s.h>
61 #include <sys/unistat/spcs_s_k.h>
62 #include <sys/unistat/spcs_errors.h>
63
64 #include "rdc_io.h"
65 #include "rdc_clnt.h"
66
67
68 /*
69 * Forward declarations.
70 */
71
72 static void rdc_update_health(rdc_if_t *);
73
74 /*
75 * Global data.
76 */
77
78 /*
79 * These structures are added when a new host name is introduced to the
80 * kernel. They never disappear (but that won't waste much space at all).
81 */
82 typedef struct rdc_link_down {
83 char host[MAX_RDC_HOST_SIZE]; /* The host name of this link */
84 int waiting; /* A user is waiting to be woken up */
85 int link_down; /* The current state of the link */
86 struct rdc_link_down *next; /* Chain */
87 kcondvar_t syncd_cv; /* Syncd wakeup */
88 kmutex_t syncd_mutex; /* Lock for syncd_cv */
89 } rdc_link_down_t;
90 static rdc_link_down_t *rdc_link_down = NULL;
91
92 int rdc_health_thres = RDC_HEALTH_THRESHOLD;
93 rdc_if_t *rdc_if_top;
94
95
96 /*
97 * IPv6 addresses are represented as 16bit hexadecimal integers
98 * separated by colons. Contiguous runs of zeros can be abbreviated by
99 * double colons:
100 * FF02:0:0:0:0:1:200E:8C6C
101 * |
102 * v
103 * FF02::1:200E:8C6C
104 */
105 void
rdc_if_ipv6(const uint16_t * addr,char * buf)106 rdc_if_ipv6(const uint16_t *addr, char *buf)
107 {
108 const int end = 8; /* 8 shorts, 128 bits in an IPv6 address */
109 int i;
110
111 for (i = 0; i < end; i++) {
112 if (i > 0)
113 (void) sprintf(buf, "%s:", buf);
114
115 if (addr[i] != 0 || i == 0 || i == (end - 1)) {
116 /* first, last, or non-zero value */
117 (void) sprintf(buf, "%s%x", buf, (int)addr[i]);
118 } else {
119 if ((i + 1) < end && addr[i + 1] != 0) {
120 /* single zero */
121 (void) sprintf(buf, "%s%x", buf, (int)addr[i]);
122 } else {
123 /* skip contiguous zeros */
124 while ((i + 1) < end && addr[i + 1] == 0)
125 i++;
126 }
127 }
128 }
129 }
130
131 static void
rdc_if_xxx(rdc_if_t * ip,char * updown)132 rdc_if_xxx(rdc_if_t *ip, char *updown)
133 {
134 if (strcmp("inet6", ip->srv->ri_knconf->knc_protofmly) == 0) {
135 uint16_t *this = (uint16_t *)ip->ifaddr.buf;
136 uint16_t *other = (uint16_t *)ip->r_ifaddr.buf;
137 char this_str[256], other_str[256];
138
139 bzero(this_str, sizeof (this_str));
140 bzero(other_str, sizeof (other_str));
141 rdc_if_ipv6(&this[4], this_str);
142 rdc_if_ipv6(&other[4], other_str);
143
144 cmn_err(CE_NOTE, "!SNDR: Interface %s <==> %s : %s",
145 this_str, other_str, updown);
146 } else {
147 uchar_t *this = (uchar_t *)ip->ifaddr.buf;
148 uchar_t *other = (uchar_t *)ip->r_ifaddr.buf;
149
150 cmn_err(CE_NOTE,
151 "!SNDR: Interface %d.%d.%d.%d <==> %d.%d.%d.%d : %s",
152 (int)this[4], (int)this[5], (int)this[6], (int)this[7],
153 (int)other[4], (int)other[5], (int)other[6], (int)other[7],
154 updown);
155 }
156 }
157
158
159 static void
rdc_if_down(rdc_if_t * ip)160 rdc_if_down(rdc_if_t *ip)
161 {
162 rdc_if_xxx(ip, "Down");
163 }
164
165
166 static void
rdc_if_up(rdc_if_t * ip)167 rdc_if_up(rdc_if_t *ip)
168 {
169 rdc_if_xxx(ip, "Up");
170 }
171
172
173 /*
174 * Health monitor for a single interface.
175 *
176 * The secondary sends ping RPCs to the primary.
177 * The primary just stores the results and updates its structures.
178 */
179 static void
rdc_health_thread(void * arg)180 rdc_health_thread(void *arg)
181 {
182 rdc_if_t *ip = (rdc_if_t *)arg;
183 struct rdc_ping ping;
184 struct rdc_ping6 ping6;
185 struct timeval t;
186 int down = 1;
187 int ret, err;
188 int sec = 0;
189 char ifaddr[RDC_MAXADDR];
190 char r_ifaddr[RDC_MAXADDR];
191 uint16_t *sp;
192
193 bcopy(ip->ifaddr.buf, ifaddr, ip->ifaddr.len);
194 sp = (uint16_t *)ifaddr;
195 *sp = htons(*sp);
196 bcopy(ip->r_ifaddr.buf, r_ifaddr, ip->r_ifaddr.len);
197 sp = (uint16_t *)r_ifaddr;
198 *sp = htons(*sp);
199
200 while ((ip->exiting != 1) && (net_exit != ATM_EXIT)) {
201 delay(HZ);
202
203 /* setup RPC timeout */
204
205 t.tv_sec = rdc_rpc_tmout;
206 t.tv_usec = 0;
207
208 if (ip->issecondary && !ip->no_ping) {
209 if (ip->rpc_version < RDC_VERSION7) {
210 bcopy(ip->r_ifaddr.buf, ping6.p_ifaddr,
211 RDC_MAXADDR);
212 /* primary ifaddr */
213 bcopy(ip->ifaddr.buf, ping6.s_ifaddr,
214 RDC_MAXADDR);
215 /* secondary ifaddr */
216 err = rdc_clnt_call_any(ip->srv, ip,
217 RDCPROC_PING4, xdr_rdc_ping6,
218 (char *)&ping6, xdr_int, (char *)&ret, &t);
219 } else {
220 ping.p_ifaddr.buf = r_ifaddr;
221 ping.p_ifaddr.len = ip->r_ifaddr.len;
222 ping.p_ifaddr.maxlen = ip->r_ifaddr.len;
223 ping.s_ifaddr.buf = ifaddr;
224 ping.s_ifaddr.len = ip->ifaddr.len;
225 ping.s_ifaddr.maxlen = ip->ifaddr.len;
226 err = rdc_clnt_call_any(ip->srv, ip,
227 RDCPROC_PING4, xdr_rdc_ping, (char *)&ping,
228 xdr_int, (char *)&ret, &t);
229 }
230
231
232 if (err || ret) {
233 /* RPC failed - link is down */
234 if (!down && !ip->isprimary) {
235 /*
236 * don't print messages if also
237 * a primary - the primary will
238 * take care of it.
239 */
240 rdc_if_down(ip);
241 down = 1;
242 }
243 rdc_dump_alloc_bufs(ip);
244 ip->no_ping = 1;
245
246 /*
247 * Start back at the max possible version
248 * since the remote server could come back
249 * on a different protocol version.
250 */
251 mutex_enter(&rdc_ping_lock);
252 ip->rpc_version = RDC_VERS_MAX;
253 mutex_exit(&rdc_ping_lock);
254 } else {
255 if (down && !ip->isprimary) {
256 /*
257 * was failed, but now ok
258 *
259 * don't print messages if also
260 * a primary - the primary will
261 * take care of it.
262 */
263 rdc_if_up(ip);
264 down = 0;
265 }
266 }
267 }
268 if (!ip->isprimary && down && ++sec == 5) {
269 sec = 0;
270 rdc_dump_alloc_bufs(ip);
271 }
272
273 if (ip->isprimary)
274 rdc_update_health(ip);
275 }
276
277 /* signal that this thread is done */
278 ip->exiting = 2;
279 }
280
281
282 int
rdc_isactive_if(struct netbuf * addr,struct netbuf * r_addr)283 rdc_isactive_if(struct netbuf *addr, struct netbuf *r_addr)
284 {
285 rdc_if_t *ip;
286 int rc = 0;
287
288 /* search for existing interface structure */
289
290 mutex_enter(&rdc_ping_lock);
291 for (ip = rdc_if_top; ip; ip = ip->next) {
292 if (ip->exiting != 0)
293 continue;
294 if (((bcmp(ip->ifaddr.buf, addr->buf, addr->len) == 0) &&
295 (bcmp(ip->r_ifaddr.buf, r_addr->buf, r_addr->len) == 0)) ||
296 ((bcmp(ip->r_ifaddr.buf, addr->buf, addr->len) == 0) &&
297 (bcmp(ip->ifaddr.buf, r_addr->buf, r_addr->len) == 0))) {
298 /* found matching interface structure */
299 if (ip->isprimary && !ip->if_down) {
300 rc = 1;
301 } else if (ip->issecondary && !ip->no_ping) {
302 rc = 1;
303 }
304 break;
305 }
306 }
307 mutex_exit(&rdc_ping_lock);
308 return (rc);
309 }
310
311 /*
312 * Set the rdc rpc version of the rdc_if_t.
313 *
314 * Called from incoming rpc calls which start before
315 * the health service becomes established.
316 */
317 void
rdc_set_if_vers(rdc_u_info_t * urdc,rpcvers_t vers)318 rdc_set_if_vers(rdc_u_info_t *urdc, rpcvers_t vers)
319 {
320 rdc_if_t *ip;
321 struct netbuf *addr, *r_addr;
322
323 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
324 addr = &(urdc->primary.addr);
325 r_addr = &(urdc->secondary.addr);
326 } else {
327 addr = &(urdc->secondary.addr);
328 r_addr = &(urdc->primary.addr);
329 }
330
331 /* search for existing interface structure */
332
333 mutex_enter(&rdc_ping_lock);
334 for (ip = rdc_if_top; ip; ip = ip->next) {
335 if (ip->exiting != 0)
336 continue;
337 if (((bcmp(ip->ifaddr.buf, addr->buf, addr->len) == 0) &&
338 (bcmp(ip->r_ifaddr.buf, r_addr->buf, r_addr->len) == 0)) ||
339 ((bcmp(ip->r_ifaddr.buf, addr->buf, addr->len) == 0) &&
340 (bcmp(ip->ifaddr.buf, r_addr->buf, r_addr->len) == 0))) {
341 /* found matching interface structure */
342 ip->rpc_version = vers;
343 #ifdef DEBUG
344 cmn_err(CE_NOTE, "!rdc intf %p rpc version set to %u",
345 (void *)ip, vers);
346 #endif
347 break;
348 }
349 }
350 mutex_exit(&rdc_ping_lock);
351 }
352
353 /*
354 * Free all the rdc_link_down structures (only at module unload time)
355 */
356 void
rdc_link_down_free()357 rdc_link_down_free()
358 {
359 rdc_link_down_t *p;
360 rdc_link_down_t *q;
361
362 if (rdc_link_down == NULL)
363 return;
364
365 for (p = rdc_link_down->next; p != rdc_link_down; ) {
366 q = p;
367 p = p->next;
368 kmem_free(q, sizeof (*q));
369 }
370 kmem_free(rdc_link_down, sizeof (*q));
371 rdc_link_down = NULL;
372 }
373
374
375 /*
376 * Look up the supplied hostname in the rdc_link_down chain. Add a new
377 * entry if it isn't found. Return a pointer to the new or found entry.
378 */
379 static rdc_link_down_t *
rdc_lookup_host(char * host)380 rdc_lookup_host(char *host)
381 {
382 rdc_link_down_t *p;
383
384 mutex_enter(&rdc_ping_lock);
385
386 if (rdc_link_down == NULL) {
387 rdc_link_down = kmem_zalloc(sizeof (*rdc_link_down), KM_SLEEP);
388 rdc_link_down->next = rdc_link_down;
389 }
390
391 for (p = rdc_link_down->next; p != rdc_link_down; p = p->next) {
392 if (strcmp(host, p->host) == 0) {
393 /* Match */
394 mutex_exit(&rdc_ping_lock);
395 return (p);
396 }
397 }
398
399 /* No match, must create a new entry */
400
401 p = kmem_zalloc(sizeof (*p), KM_SLEEP);
402 p->link_down = 1;
403 p->next = rdc_link_down->next;
404 rdc_link_down->next = p;
405 (void) strncpy(p->host, host, MAX_RDC_HOST_SIZE);
406 mutex_init(&p->syncd_mutex, NULL, MUTEX_DRIVER, NULL);
407 cv_init(&p->syncd_cv, NULL, CV_DRIVER, NULL);
408
409 mutex_exit(&rdc_ping_lock);
410 return (p);
411 }
412
413
414 /*
415 * Handle the RDC_LINK_DOWN ioctl.
416 * The user specifies which host he is interested in.
417 * This function is woken up when the link to that host goes down.
418 */
419
420 /* ARGSUSED3 */
421 int
_rdc_link_down(void * arg,int mode,spcs_s_info_t kstatus,int * rvp)422 _rdc_link_down(void *arg, int mode, spcs_s_info_t kstatus, int *rvp)
423 {
424 char host[MAX_RDC_HOST_SIZE];
425 rdc_link_down_t *syncdp;
426 clock_t timeout = RDC_SYNC_EVENT_TIMEOUT * 2; /* 2 min */
427 int rc = 0;
428
429 if (ddi_copyin(arg, host, MAX_RDC_HOST_SIZE, mode))
430 return (EFAULT);
431
432
433 syncdp = rdc_lookup_host(host);
434
435 mutex_enter(&syncdp->syncd_mutex);
436 if (!syncdp->link_down) {
437 syncdp->waiting = 1;
438 if (cv_timedwait_sig(&syncdp->syncd_cv, &syncdp->syncd_mutex,
439 nsc_lbolt() + timeout) == 0) {
440 /* Woken by a signal, not a link down event */
441 syncdp->waiting = 0;
442 rc = EAGAIN;
443 spcs_s_add(kstatus, rc);
444 }
445
446 }
447 mutex_exit(&syncdp->syncd_mutex);
448
449 return (rc);
450 }
451
452
453 /*
454 * Add an RDC set to an interface
455 *
456 * If the interface is new, add it to the list of interfaces.
457 */
458 rdc_if_t *
rdc_add_to_if(rdc_srv_t * svp,struct netbuf * addr,struct netbuf * r_addr,int primary)459 rdc_add_to_if(rdc_srv_t *svp, struct netbuf *addr, struct netbuf *r_addr,
460 int primary)
461 {
462 rdc_if_t *new, *ip;
463
464 if ((addr->buf == NULL) || (r_addr->buf == NULL))
465 return (NULL);
466
467 /* setup a new interface structure */
468 new = (rdc_if_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
469 if (!new)
470 return (NULL);
471
472 dup_rdc_netbuf(addr, &new->ifaddr);
473 dup_rdc_netbuf(r_addr, &new->r_ifaddr);
474 new->rpc_version = RDC_VERS_MAX;
475 new->srv = rdc_create_svinfo(svp->ri_hostname, &svp->ri_addr,
476 svp->ri_knconf);
477 new->old_pulse = -1;
478 new->new_pulse = 0;
479
480 if (!new->srv) {
481 free_rdc_netbuf(&new->r_ifaddr);
482 free_rdc_netbuf(&new->ifaddr);
483 kmem_free(new, sizeof (*new));
484 return (NULL);
485 }
486
487 /* search for existing interface structure */
488
489 mutex_enter(&rdc_ping_lock);
490
491 for (ip = rdc_if_top; ip; ip = ip->next) {
492 if ((bcmp(ip->ifaddr.buf, addr->buf, addr->len) == 0) &&
493 (bcmp(ip->r_ifaddr.buf, r_addr->buf, r_addr->len) == 0) &&
494 ip->exiting == 0) {
495 /* found matching interface structure */
496 break;
497 }
498 }
499
500 if (!ip) {
501 /* add new into the chain */
502
503 new->next = rdc_if_top;
504 rdc_if_top = new;
505 ip = new;
506
507 /* start daemon */
508
509 ip->last = nsc_time();
510 ip->deadness = 1;
511 ip->if_down = 1;
512
513 if (nsc_create_process(rdc_health_thread, ip, TRUE)) {
514 mutex_exit(&rdc_ping_lock);
515 return (NULL);
516 }
517 }
518
519 /* mark usage type */
520
521 if (primary) {
522 ip->isprimary = 1;
523 } else {
524 ip->issecondary = 1;
525 ip->no_ping = 0;
526 }
527
528 mutex_exit(&rdc_ping_lock);
529
530 /* throw away new if it was not used */
531
532 if (ip != new) {
533 free_rdc_netbuf(&new->r_ifaddr);
534 free_rdc_netbuf(&new->ifaddr);
535 rdc_destroy_svinfo(new->srv);
536 kmem_free(new, sizeof (*new));
537 }
538
539 return (ip);
540 }
541
542
543 /*
544 * Update an interface following the removal of an RDC set.
545 *
546 * If there are no more RDC sets using the interface, delete it from
547 * the list of interfaces.
548 *
549 * Either clear krdc->intf, or ensure !IS_CONFIGURED(krdc) before calling this.
550 */
551 void
rdc_remove_from_if(rdc_if_t * ip)552 rdc_remove_from_if(rdc_if_t *ip)
553 {
554 rdc_k_info_t *krdc;
555 rdc_u_info_t *urdc;
556 rdc_if_t **ipp;
557 int pfound = 0;
558 int sfound = 0;
559 int delete = 1;
560 int index;
561
562 mutex_enter(&rdc_ping_lock);
563
564 /*
565 * search for RDC sets using this interface and update
566 * the isprimary and issecondary flags.
567 */
568
569 for (index = 0; index < rdc_max_sets; index++) {
570 krdc = &rdc_k_info[index];
571 urdc = &rdc_u_info[index];
572 if (IS_CONFIGURED(krdc) && krdc->intf == ip) {
573 delete = 0;
574
575 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
576 pfound = 1;
577 } else {
578 sfound = 1;
579 }
580
581 if (pfound && sfound)
582 break;
583 }
584 }
585
586 ip->isprimary = pfound;
587 ip->issecondary = sfound;
588
589 if (!delete || ip->exiting > 0) {
590 mutex_exit(&rdc_ping_lock);
591 return;
592 }
593
594 /* mark and wait for daemon to exit */
595
596 ip->exiting = 1;
597
598 mutex_exit(&rdc_ping_lock);
599
600 while (ip->exiting == 1)
601 delay(drv_usectohz(10));
602
603 mutex_enter(&rdc_ping_lock);
604
605 ASSERT(ip->exiting == 2);
606
607 /* remove from chain */
608
609 for (ipp = &rdc_if_top; *ipp; ipp = &((*ipp)->next)) {
610 if (*ipp == ip) {
611 *ipp = ip->next;
612 break;
613 }
614 }
615
616 mutex_exit(&rdc_ping_lock);
617
618 /* free unused interface structure */
619
620 free_rdc_netbuf(&ip->r_ifaddr);
621 free_rdc_netbuf(&ip->ifaddr);
622 rdc_destroy_svinfo(ip->srv);
623 kmem_free(ip, sizeof (*ip));
624 }
625
626
627 /*
628 * Check the status of the link to the secondary, and optionally update
629 * the primary-side ping variables.
630 *
631 * For use on a primary only.
632 *
633 * Returns:
634 * TRUE - interface up.
635 * FALSE - interface down.
636 */
637 int
rdc_check_secondary(rdc_if_t * ip,int update)638 rdc_check_secondary(rdc_if_t *ip, int update)
639 {
640 int rc = TRUE;
641
642 if (!ip || !ip->isprimary) {
643 #ifdef DEBUG
644 cmn_err(CE_WARN,
645 "!rdc_check_secondary: ip %p, isprimary %d, issecondary %d",
646 (void *) ip, ip ? ip->isprimary : 0,
647 ip ? ip->issecondary : 0);
648 #endif
649 return (FALSE);
650 }
651
652 if (!ip->deadness) {
653 #ifdef DEBUG
654 cmn_err(CE_WARN, "!rdc_check_secondary: ip %p, ip->deadness %d",
655 (void *) ip, ip->deadness);
656 #endif
657 return (FALSE);
658 }
659
660 if (!update) {
661 /* quick look */
662 return ((ip->deadness > rdc_health_thres) ? FALSE : TRUE);
663 }
664
665 /* update (slow) with lock */
666
667 mutex_enter(&rdc_ping_lock);
668
669 if (ip->old_pulse == ip->new_pulse) {
670 /*
671 * ping has not been received since last update
672 * or we have not yet been pinged,
673 * the health thread has started only as a
674 * local client so far, not so on the other side
675 */
676
677 if (ip->last != nsc_time()) {
678 /* time has passed, so move closer to death */
679
680 ip->last = nsc_time();
681 ip->deadness++;
682
683 if (ip->deadness <= 0) {
684 /* avoid the wrap */
685 ip->deadness = rdc_health_thres + 1;
686 }
687 }
688
689 if (ip->deadness > rdc_health_thres) {
690 rc = FALSE;
691 /*
692 * Start back at the max possible version
693 * since the remote server could come back
694 * on a different protocol version.
695 */
696 ip->rpc_version = RDC_VERS_MAX;
697 }
698 } else {
699 ip->old_pulse = ip->new_pulse;
700 }
701
702 mutex_exit(&rdc_ping_lock);
703 return (rc);
704 }
705
706
707 /*
708 * Update the interface structure with the latest ping info, and
709 * perform interface up/down transitions if required.
710 *
711 * For use on a primary only.
712 */
713 static void
rdc_update_health(rdc_if_t * ip)714 rdc_update_health(rdc_if_t *ip)
715 {
716 rdc_k_info_t *krdc;
717 rdc_u_info_t *urdc;
718 int index;
719 rdc_link_down_t *syncdp;
720
721 if (!ip->isprimary) {
722 #ifdef DEBUG
723 cmn_err(CE_WARN,
724 "!rdc_update_health: ip %p, isprimary %d, issecondary %d",
725 (void *) ip, ip ? ip->isprimary : 0,
726 ip ? ip->issecondary : 0);
727 #endif
728 return;
729 }
730
731 if (!rdc_check_secondary(ip, TRUE)) {
732 /* interface down */
733 if (!ip->if_down) {
734 rdc_if_down(ip);
735 ip->if_down = 1;
736
737 /* scan rdc sets and update status */
738
739 for (index = 0; index < rdc_max_sets; index++) {
740 krdc = &rdc_k_info[index];
741 urdc = &rdc_u_info[index];
742
743 if (IS_ENABLED(urdc) && (krdc->intf == ip) &&
744 (rdc_get_vflags(urdc) & RDC_PRIMARY) &&
745 !(rdc_get_vflags(urdc) & RDC_LOGGING)) {
746 /* mark down */
747
748 rdc_group_enter(krdc);
749 /*
750 * check for possible race with
751 * with delete logic
752 */
753 if (!IS_ENABLED(urdc)) {
754 rdc_group_exit(krdc);
755 continue;
756 }
757 rdc_group_log(krdc, RDC_NOFLUSH |
758 RDC_NOREMOTE | RDC_QUEUING,
759 "hm detected secondary "
760 "interface down");
761
762 rdc_group_exit(krdc);
763
764 /* dump async queues */
765 rdc_dump_queue(index);
766 }
767 }
768
769 /* dump allocated bufs */
770 rdc_dump_alloc_bufs(ip);
771 }
772
773 syncdp = rdc_lookup_host(ip->srv->ri_hostname);
774 mutex_enter(&syncdp->syncd_mutex);
775 if (syncdp->link_down == 0) {
776 /* Link has gone down, notify rdcsyncd daemon */
777 syncdp->link_down = 1;
778 if (syncdp->waiting) {
779 syncdp->waiting = 0;
780 cv_signal(&syncdp->syncd_cv);
781 }
782 }
783 mutex_exit(&syncdp->syncd_mutex);
784 } else {
785 /* interface up */
786 if (ip->if_down && ip->isprimary) {
787 rdc_if_up(ip);
788 ip->if_down = 0;
789 }
790
791 syncdp = rdc_lookup_host(ip->srv->ri_hostname);
792 mutex_enter(&syncdp->syncd_mutex);
793 if (syncdp->link_down) {
794 /* Link has come back up */
795 syncdp->link_down = 0;
796 }
797 mutex_exit(&syncdp->syncd_mutex);
798 }
799 }
800