1*dbed73cbSSangeeta Misra /*
2*dbed73cbSSangeeta Misra  * CDDL HEADER START
3*dbed73cbSSangeeta Misra  *
4*dbed73cbSSangeeta Misra  * The contents of this file are subject to the terms of the
5*dbed73cbSSangeeta Misra  * Common Development and Distribution License (the "License").
6*dbed73cbSSangeeta Misra  * You may not use this file except in compliance with the License.
7*dbed73cbSSangeeta Misra  *
8*dbed73cbSSangeeta Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*dbed73cbSSangeeta Misra  * or http://www.opensolaris.org/os/licensing.
10*dbed73cbSSangeeta Misra  * See the License for the specific language governing permissions
11*dbed73cbSSangeeta Misra  * and limitations under the License.
12*dbed73cbSSangeeta Misra  *
13*dbed73cbSSangeeta Misra  * When distributing Covered Code, include this CDDL HEADER in each
14*dbed73cbSSangeeta Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*dbed73cbSSangeeta Misra  * If applicable, add the following below this CDDL HEADER, with the
16*dbed73cbSSangeeta Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17*dbed73cbSSangeeta Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18*dbed73cbSSangeeta Misra  *
19*dbed73cbSSangeeta Misra  * CDDL HEADER END
20*dbed73cbSSangeeta Misra  */
21*dbed73cbSSangeeta Misra 
22*dbed73cbSSangeeta Misra /*
23*dbed73cbSSangeeta Misra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*dbed73cbSSangeeta Misra  * Use is subject to license terms.
25*dbed73cbSSangeeta Misra  */
26*dbed73cbSSangeeta Misra 
27*dbed73cbSSangeeta Misra #include <sys/types.h>
28*dbed73cbSSangeeta Misra #include <sys/socket.h>
29*dbed73cbSSangeeta Misra #include <sys/list.h>
30*dbed73cbSSangeeta Misra #include <sys/stropts.h>
31*dbed73cbSSangeeta Misra #include <sys/siginfo.h>
32*dbed73cbSSangeeta Misra #include <sys/wait.h>
33*dbed73cbSSangeeta Misra #include <arpa/inet.h>
34*dbed73cbSSangeeta Misra #include <netinet/in.h>
35*dbed73cbSSangeeta Misra #include <stdlib.h>
36*dbed73cbSSangeeta Misra #include <stdio.h>
37*dbed73cbSSangeeta Misra #include <strings.h>
38*dbed73cbSSangeeta Misra #include <stddef.h>
39*dbed73cbSSangeeta Misra #include <unistd.h>
40*dbed73cbSSangeeta Misra #include <libilb.h>
41*dbed73cbSSangeeta Misra #include <port.h>
42*dbed73cbSSangeeta Misra #include <time.h>
43*dbed73cbSSangeeta Misra #include <signal.h>
44*dbed73cbSSangeeta Misra #include <assert.h>
45*dbed73cbSSangeeta Misra #include <errno.h>
46*dbed73cbSSangeeta Misra #include <spawn.h>
47*dbed73cbSSangeeta Misra #include <fcntl.h>
48*dbed73cbSSangeeta Misra #include <limits.h>
49*dbed73cbSSangeeta Misra #include "libilb_impl.h"
50*dbed73cbSSangeeta Misra #include "ilbd.h"
51*dbed73cbSSangeeta Misra 
52*dbed73cbSSangeeta Misra /* Global list of HC objects */
53*dbed73cbSSangeeta Misra list_t ilbd_hc_list;
54*dbed73cbSSangeeta Misra 
55*dbed73cbSSangeeta Misra /* Timer queue for all hc related timers. */
56*dbed73cbSSangeeta Misra static iu_tq_t *ilbd_hc_timer_q;
57*dbed73cbSSangeeta Misra 
58*dbed73cbSSangeeta Misra /* Indicate whether the timer needs to be updated */
59*dbed73cbSSangeeta Misra static boolean_t hc_timer_restarted;
60*dbed73cbSSangeeta Misra 
61*dbed73cbSSangeeta Misra static void ilbd_hc_probe_timer(iu_tq_t *, void *);
62*dbed73cbSSangeeta Misra static ilb_status_t ilbd_hc_restart_timer(ilbd_hc_t *, ilbd_hc_srv_t *);
63*dbed73cbSSangeeta Misra static boolean_t ilbd_run_probe(ilbd_hc_srv_t *);
64*dbed73cbSSangeeta Misra 
65*dbed73cbSSangeeta Misra #define	MAX(a, b)	((a) > (b) ? (a) : (b))
66*dbed73cbSSangeeta Misra 
67*dbed73cbSSangeeta Misra /*
68*dbed73cbSSangeeta Misra  * Number of arguments passed to a probe.  argc[0] is the path name of
69*dbed73cbSSangeeta Misra  * the probe.
70*dbed73cbSSangeeta Misra  */
71*dbed73cbSSangeeta Misra #define	HC_PROBE_ARGC	8
72*dbed73cbSSangeeta Misra 
73*dbed73cbSSangeeta Misra /*
74*dbed73cbSSangeeta Misra  * Max number of characters to be read from the output of a probe.  It
75*dbed73cbSSangeeta Misra  * is long enough to read in a 64 bit integer.
76*dbed73cbSSangeeta Misra  */
77*dbed73cbSSangeeta Misra #define	HC_MAX_PROBE_OUTPUT	24
78*dbed73cbSSangeeta Misra 
79*dbed73cbSSangeeta Misra void
80*dbed73cbSSangeeta Misra i_ilbd_setup_hc_list(void)
81*dbed73cbSSangeeta Misra {
82*dbed73cbSSangeeta Misra 	list_create(&ilbd_hc_list, sizeof (ilbd_hc_t),
83*dbed73cbSSangeeta Misra 	    offsetof(ilbd_hc_t, ihc_link));
84*dbed73cbSSangeeta Misra }
85*dbed73cbSSangeeta Misra 
86*dbed73cbSSangeeta Misra /*
87*dbed73cbSSangeeta Misra  * Given a hc object name, return a pointer to hc object if found.
88*dbed73cbSSangeeta Misra  */
89*dbed73cbSSangeeta Misra ilbd_hc_t *
90*dbed73cbSSangeeta Misra ilbd_get_hc(const char *name)
91*dbed73cbSSangeeta Misra {
92*dbed73cbSSangeeta Misra 	ilbd_hc_t *hc;
93*dbed73cbSSangeeta Misra 
94*dbed73cbSSangeeta Misra 	for (hc = list_head(&ilbd_hc_list); hc != NULL;
95*dbed73cbSSangeeta Misra 	    hc = list_next(&ilbd_hc_list, hc)) {
96*dbed73cbSSangeeta Misra 		if (strcasecmp(hc->ihc_name, name) == 0)
97*dbed73cbSSangeeta Misra 			return (hc);
98*dbed73cbSSangeeta Misra 	}
99*dbed73cbSSangeeta Misra 	return (NULL);
100*dbed73cbSSangeeta Misra }
101*dbed73cbSSangeeta Misra 
102*dbed73cbSSangeeta Misra /*
103*dbed73cbSSangeeta Misra  * Generates an audit record for create-healthcheck,
104*dbed73cbSSangeeta Misra  * delete-healtcheck subcommands.
105*dbed73cbSSangeeta Misra  */
106*dbed73cbSSangeeta Misra static void
107*dbed73cbSSangeeta Misra ilbd_audit_hc_event(const char *audit_hcname,
108*dbed73cbSSangeeta Misra     const ilb_hc_info_t *audit_hcinfo, ilbd_cmd_t cmd,
109*dbed73cbSSangeeta Misra     ilb_status_t rc, ucred_t *ucredp)
110*dbed73cbSSangeeta Misra {
111*dbed73cbSSangeeta Misra 	adt_session_data_t	*ah;
112*dbed73cbSSangeeta Misra 	adt_event_data_t	*event;
113*dbed73cbSSangeeta Misra 	au_event_t	flag;
114*dbed73cbSSangeeta Misra 	int	audit_error;
115*dbed73cbSSangeeta Misra 
116*dbed73cbSSangeeta Misra 	if ((ucredp == NULL) && (cmd == ILBD_CREATE_HC))  {
117*dbed73cbSSangeeta Misra 		/*
118*dbed73cbSSangeeta Misra 		 * we came here from the path where ilbd incorporates
119*dbed73cbSSangeeta Misra 		 * the configuration that is listed in SCF:
120*dbed73cbSSangeeta Misra 		 * i_ilbd_read_config->ilbd_walk_hc_pgs->
121*dbed73cbSSangeeta Misra 		 *   ->ilbd_scf_instance_walk_pg->ilbd_create_hc
122*dbed73cbSSangeeta Misra 		 * We skip auditing in that case
123*dbed73cbSSangeeta Misra 		 */
124*dbed73cbSSangeeta Misra 		logdebug("ilbd_audit_hc_event: skipping auditing");
125*dbed73cbSSangeeta Misra 		return;
126*dbed73cbSSangeeta Misra 	}
127*dbed73cbSSangeeta Misra 
128*dbed73cbSSangeeta Misra 	if (adt_start_session(&ah, NULL, 0) != 0) {
129*dbed73cbSSangeeta Misra 		logerr("ilbd_audit_hc_event: adt_start_session failed");
130*dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
131*dbed73cbSSangeeta Misra 	}
132*dbed73cbSSangeeta Misra 	if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) {
133*dbed73cbSSangeeta Misra 		(void) adt_end_session(ah);
134*dbed73cbSSangeeta Misra 		logerr("ilbd_audit_rule_event: adt_set_from_ucred failed");
135*dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
136*dbed73cbSSangeeta Misra 	}
137*dbed73cbSSangeeta Misra 	if (cmd == ILBD_CREATE_HC)
138*dbed73cbSSangeeta Misra 		flag = ADT_ilb_create_healthcheck;
139*dbed73cbSSangeeta Misra 	else if (cmd == ILBD_DESTROY_HC)
140*dbed73cbSSangeeta Misra 		flag = ADT_ilb_delete_healthcheck;
141*dbed73cbSSangeeta Misra 
142*dbed73cbSSangeeta Misra 	if ((event = adt_alloc_event(ah, flag)) == NULL) {
143*dbed73cbSSangeeta Misra 		logerr("ilbd_audit_hc_event: adt_alloc_event failed");
144*dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
145*dbed73cbSSangeeta Misra 	}
146*dbed73cbSSangeeta Misra 	(void) memset((char *)event, 0, sizeof (adt_event_data_t));
147*dbed73cbSSangeeta Misra 
148*dbed73cbSSangeeta Misra 	switch (cmd) {
149*dbed73cbSSangeeta Misra 	case ILBD_CREATE_HC:
150*dbed73cbSSangeeta Misra 		event->adt_ilb_create_healthcheck.auth_used =
151*dbed73cbSSangeeta Misra 		    NET_ILB_CONFIG_AUTH;
152*dbed73cbSSangeeta Misra 		event->adt_ilb_create_healthcheck.hc_test =
153*dbed73cbSSangeeta Misra 		    (char *)audit_hcinfo->hci_test;
154*dbed73cbSSangeeta Misra 		event->adt_ilb_create_healthcheck.hc_name =
155*dbed73cbSSangeeta Misra 		    (char *)audit_hcinfo->hci_name;
156*dbed73cbSSangeeta Misra 
157*dbed73cbSSangeeta Misra 		/*
158*dbed73cbSSangeeta Misra 		 * If the value 0 is stored, the default values are
159*dbed73cbSSangeeta Misra 		 * set in the kernel. User land does not know about them
160*dbed73cbSSangeeta Misra 		 * So if the user does not specify them, audit record
161*dbed73cbSSangeeta Misra 		 * will show them as 0
162*dbed73cbSSangeeta Misra 		 */
163*dbed73cbSSangeeta Misra 		event->adt_ilb_create_healthcheck.hc_timeout =
164*dbed73cbSSangeeta Misra 		    audit_hcinfo->hci_timeout;
165*dbed73cbSSangeeta Misra 		event->adt_ilb_create_healthcheck.hc_count =
166*dbed73cbSSangeeta Misra 		    audit_hcinfo->hci_count;
167*dbed73cbSSangeeta Misra 		event->adt_ilb_create_healthcheck.hc_interval =
168*dbed73cbSSangeeta Misra 		    audit_hcinfo->hci_interval;
169*dbed73cbSSangeeta Misra 		break;
170*dbed73cbSSangeeta Misra 	case ILBD_DESTROY_HC:
171*dbed73cbSSangeeta Misra 		event->adt_ilb_delete_healthcheck.auth_used =
172*dbed73cbSSangeeta Misra 		    NET_ILB_CONFIG_AUTH;
173*dbed73cbSSangeeta Misra 		event->adt_ilb_delete_healthcheck.hc_name =
174*dbed73cbSSangeeta Misra 		    (char *)audit_hcname;
175*dbed73cbSSangeeta Misra 		break;
176*dbed73cbSSangeeta Misra 	}
177*dbed73cbSSangeeta Misra 
178*dbed73cbSSangeeta Misra 	/* Fill in success/failure */
179*dbed73cbSSangeeta Misra 	if (rc == ILB_STATUS_OK) {
180*dbed73cbSSangeeta Misra 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
181*dbed73cbSSangeeta Misra 			logerr("ilbd_audit_hc_event: adt_put_event failed");
182*dbed73cbSSangeeta Misra 			exit(EXIT_FAILURE);
183*dbed73cbSSangeeta Misra 		}
184*dbed73cbSSangeeta Misra 	} else {
185*dbed73cbSSangeeta Misra 		audit_error = ilberror2auditerror(rc);
186*dbed73cbSSangeeta Misra 		if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) {
187*dbed73cbSSangeeta Misra 			logerr("ilbd_audit_hc_event: adt_put_event failed");
188*dbed73cbSSangeeta Misra 			exit(EXIT_FAILURE);
189*dbed73cbSSangeeta Misra 		}
190*dbed73cbSSangeeta Misra 	}
191*dbed73cbSSangeeta Misra 	adt_free_event(event);
192*dbed73cbSSangeeta Misra 	(void) adt_end_session(ah);
193*dbed73cbSSangeeta Misra }
194*dbed73cbSSangeeta Misra 
195*dbed73cbSSangeeta Misra /*
196*dbed73cbSSangeeta Misra  * Given the ilb_hc_info_t passed in (from the libilb), create a hc object
197*dbed73cbSSangeeta Misra  * in ilbd.  The parameter ev_port is not used, refer to comments of
198*dbed73cbSSangeeta Misra  * ilbd_create_sg() in ilbd_sg.c
199*dbed73cbSSangeeta Misra  */
200*dbed73cbSSangeeta Misra /* ARGSUSED */
201*dbed73cbSSangeeta Misra ilb_status_t
202*dbed73cbSSangeeta Misra ilbd_create_hc(const ilb_hc_info_t *hc_info, int ev_port,
203*dbed73cbSSangeeta Misra     const struct passwd *ps, ucred_t *ucredp)
204*dbed73cbSSangeeta Misra {
205*dbed73cbSSangeeta Misra 	ilbd_hc_t *hc;
206*dbed73cbSSangeeta Misra 	ilb_status_t ret = ILB_STATUS_OK;
207*dbed73cbSSangeeta Misra 
208*dbed73cbSSangeeta Misra 	/*
209*dbed73cbSSangeeta Misra 	 * ps == NULL is from the daemon when it starts and load configuration
210*dbed73cbSSangeeta Misra 	 * ps != NULL is from client.
211*dbed73cbSSangeeta Misra 	 */
212*dbed73cbSSangeeta Misra 	if (ps != NULL) {
213*dbed73cbSSangeeta Misra 		ret = ilbd_check_client_config_auth(ps);
214*dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK) {
215*dbed73cbSSangeeta Misra 			ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
216*dbed73cbSSangeeta Misra 			    ret, ucredp);
217*dbed73cbSSangeeta Misra 			return (ret);
218*dbed73cbSSangeeta Misra 		}
219*dbed73cbSSangeeta Misra 	}
220*dbed73cbSSangeeta Misra 
221*dbed73cbSSangeeta Misra 	if (hc_info->hci_name[0] == '\0') {
222*dbed73cbSSangeeta Misra 		logdebug("ilbd_create_hc: missing healthcheck info");
223*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
224*dbed73cbSSangeeta Misra 		    ILB_STATUS_ENOHCINFO, ucredp);
225*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOHCINFO);
226*dbed73cbSSangeeta Misra 	}
227*dbed73cbSSangeeta Misra 
228*dbed73cbSSangeeta Misra 	hc = ilbd_get_hc(hc_info->hci_name);
229*dbed73cbSSangeeta Misra 	if (hc != NULL) {
230*dbed73cbSSangeeta Misra 		logdebug("ilbd_create_hc: healthcheck name %s already"
231*dbed73cbSSangeeta Misra 		    " exists", hc_info->hci_name);
232*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
233*dbed73cbSSangeeta Misra 		    ILB_STATUS_EEXIST, ucredp);
234*dbed73cbSSangeeta Misra 		return (ILB_STATUS_EEXIST);
235*dbed73cbSSangeeta Misra 	}
236*dbed73cbSSangeeta Misra 
237*dbed73cbSSangeeta Misra 	/*
238*dbed73cbSSangeeta Misra 	 * Sanity check on user supplied probe.  The given path name
239*dbed73cbSSangeeta Misra 	 * must be a full path name (starts with '/') and is
240*dbed73cbSSangeeta Misra 	 * executable.
241*dbed73cbSSangeeta Misra 	 */
242*dbed73cbSSangeeta Misra 	if (strcasecmp(hc_info->hci_test, ILB_HC_STR_TCP) != 0 &&
243*dbed73cbSSangeeta Misra 	    strcasecmp(hc_info->hci_test, ILB_HC_STR_UDP) != 0 &&
244*dbed73cbSSangeeta Misra 	    strcasecmp(hc_info->hci_test, ILB_HC_STR_PING) != 0 &&
245*dbed73cbSSangeeta Misra 	    (hc_info->hci_test[0] != '/' ||
246*dbed73cbSSangeeta Misra 	    access(hc_info->hci_test, X_OK) == -1)) {
247*dbed73cbSSangeeta Misra 		if (errno == ENOENT) {
248*dbed73cbSSangeeta Misra 			logdebug("ilbd_create_hc: user script %s doesn't "
249*dbed73cbSSangeeta Misra 			    "exist", hc_info->hci_test);
250*dbed73cbSSangeeta Misra 			ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
251*dbed73cbSSangeeta Misra 			    ILB_STATUS_ENOENT, ucredp);
252*dbed73cbSSangeeta Misra 			return (ILB_STATUS_ENOENT);
253*dbed73cbSSangeeta Misra 		} else {
254*dbed73cbSSangeeta Misra 			logdebug("ilbd_create_hc: user script %s is "
255*dbed73cbSSangeeta Misra 			    "invalid", hc_info->hci_test);
256*dbed73cbSSangeeta Misra 			ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
257*dbed73cbSSangeeta Misra 			    ILB_STATUS_EINVAL, ucredp);
258*dbed73cbSSangeeta Misra 			return (ILB_STATUS_EINVAL);
259*dbed73cbSSangeeta Misra 		}
260*dbed73cbSSangeeta Misra 	}
261*dbed73cbSSangeeta Misra 
262*dbed73cbSSangeeta Misra 	/* Create and add the hc object */
263*dbed73cbSSangeeta Misra 	hc = calloc(1, sizeof (ilbd_hc_t));
264*dbed73cbSSangeeta Misra 	if (hc == NULL) {
265*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
266*dbed73cbSSangeeta Misra 		    ILB_STATUS_ENOMEM, ucredp);
267*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
268*dbed73cbSSangeeta Misra 	}
269*dbed73cbSSangeeta Misra 	(void) memcpy(&hc->ihc_info, hc_info, sizeof (ilb_hc_info_t));
270*dbed73cbSSangeeta Misra 	if (strcasecmp(hc->ihc_test, ILB_HC_STR_TCP) == 0)
271*dbed73cbSSangeeta Misra 		hc->ihc_test_type = ILBD_HC_TCP;
272*dbed73cbSSangeeta Misra 	else if (strcasecmp(hc->ihc_test, ILB_HC_STR_UDP) == 0)
273*dbed73cbSSangeeta Misra 		hc->ihc_test_type = ILBD_HC_UDP;
274*dbed73cbSSangeeta Misra 	else if (strcasecmp(hc->ihc_test, ILB_HC_STR_PING) == 0)
275*dbed73cbSSangeeta Misra 		hc->ihc_test_type = ILBD_HC_PING;
276*dbed73cbSSangeeta Misra 	else
277*dbed73cbSSangeeta Misra 		hc->ihc_test_type = ILBD_HC_USER;
278*dbed73cbSSangeeta Misra 	list_create(&hc->ihc_rules, sizeof (ilbd_hc_rule_t),
279*dbed73cbSSangeeta Misra 	    offsetof(ilbd_hc_rule_t, hcr_link));
280*dbed73cbSSangeeta Misra 
281*dbed73cbSSangeeta Misra 	/* Update SCF */
282*dbed73cbSSangeeta Misra 	if (ps != NULL) {
283*dbed73cbSSangeeta Misra 		if ((ret = ilbd_create_pg(ILBD_SCF_HC, (void *)hc)) !=
284*dbed73cbSSangeeta Misra 		    ILB_STATUS_OK) {
285*dbed73cbSSangeeta Misra 			ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC,
286*dbed73cbSSangeeta Misra 			    ret, ucredp);
287*dbed73cbSSangeeta Misra 			free(hc);
288*dbed73cbSSangeeta Misra 			return (ret);
289*dbed73cbSSangeeta Misra 		}
290*dbed73cbSSangeeta Misra 	}
291*dbed73cbSSangeeta Misra 
292*dbed73cbSSangeeta Misra 	/* Everything is fine, now add it to the global list. */
293*dbed73cbSSangeeta Misra 	list_insert_tail(&ilbd_hc_list, hc);
294*dbed73cbSSangeeta Misra 	ilbd_audit_hc_event(NULL, hc_info, ILBD_CREATE_HC, ret, ucredp);
295*dbed73cbSSangeeta Misra 	return (ret);
296*dbed73cbSSangeeta Misra }
297*dbed73cbSSangeeta Misra 
298*dbed73cbSSangeeta Misra /*
299*dbed73cbSSangeeta Misra  * Given a name of a hc object, destroy it.
300*dbed73cbSSangeeta Misra  */
301*dbed73cbSSangeeta Misra ilb_status_t
302*dbed73cbSSangeeta Misra ilbd_destroy_hc(const char *hc_name, const struct passwd *ps,
303*dbed73cbSSangeeta Misra     ucred_t *ucredp)
304*dbed73cbSSangeeta Misra {
305*dbed73cbSSangeeta Misra 	ilb_status_t ret;
306*dbed73cbSSangeeta Misra 	ilbd_hc_t *hc;
307*dbed73cbSSangeeta Misra 
308*dbed73cbSSangeeta Misra 	/*
309*dbed73cbSSangeeta Misra 	 * No need to check ps == NULL, daemon won't call any destroy func
310*dbed73cbSSangeeta Misra 	 * at start up.
311*dbed73cbSSangeeta Misra 	 */
312*dbed73cbSSangeeta Misra 	ret = ilbd_check_client_config_auth(ps);
313*dbed73cbSSangeeta Misra 	if (ret != ILB_STATUS_OK) {
314*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(hc_name, NULL, ILBD_DESTROY_HC,
315*dbed73cbSSangeeta Misra 		    ret, ucredp);
316*dbed73cbSSangeeta Misra 		return (ret);
317*dbed73cbSSangeeta Misra 	}
318*dbed73cbSSangeeta Misra 
319*dbed73cbSSangeeta Misra 	hc = ilbd_get_hc(hc_name);
320*dbed73cbSSangeeta Misra 	if (hc == NULL) {
321*dbed73cbSSangeeta Misra 		logdebug("ilbd_destroy_hc: healthcheck %s does not exist",
322*dbed73cbSSangeeta Misra 		    hc_name);
323*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(hc_name, NULL, ILBD_DESTROY_HC,
324*dbed73cbSSangeeta Misra 		    ILB_STATUS_ENOENT, ucredp);
325*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
326*dbed73cbSSangeeta Misra 	}
327*dbed73cbSSangeeta Misra 
328*dbed73cbSSangeeta Misra 	/* If hc is in use, cannot delete it */
329*dbed73cbSSangeeta Misra 	if (hc->ihc_rule_cnt > 0) {
330*dbed73cbSSangeeta Misra 		logdebug("ilbd_destroy_hc: healthcheck %s is associated"
331*dbed73cbSSangeeta Misra 		    " with a rule - cannot remove", hc_name);
332*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(hc_name, NULL, ILBD_DESTROY_HC,
333*dbed73cbSSangeeta Misra 		    ILB_STATUS_INUSE, ucredp);
334*dbed73cbSSangeeta Misra 		return (ILB_STATUS_INUSE);
335*dbed73cbSSangeeta Misra 	}
336*dbed73cbSSangeeta Misra 
337*dbed73cbSSangeeta Misra 	if ((ret = ilbd_destroy_pg(ILBD_SCF_HC, hc_name)) !=
338*dbed73cbSSangeeta Misra 	    ILB_STATUS_OK) {
339*dbed73cbSSangeeta Misra 		logdebug("ilbd_destroy_hc: cannot destroy healthcheck %s "
340*dbed73cbSSangeeta Misra 		    "property group", hc_name);
341*dbed73cbSSangeeta Misra 		ilbd_audit_hc_event(hc_name, NULL, ILBD_DESTROY_HC,
342*dbed73cbSSangeeta Misra 		    ret, ucredp);
343*dbed73cbSSangeeta Misra 		return (ret);
344*dbed73cbSSangeeta Misra 	}
345*dbed73cbSSangeeta Misra 
346*dbed73cbSSangeeta Misra 	list_remove(&ilbd_hc_list, hc);
347*dbed73cbSSangeeta Misra 	free(hc);
348*dbed73cbSSangeeta Misra 	ilbd_audit_hc_event(hc_name, NULL, ILBD_DESTROY_HC, ret, ucredp);
349*dbed73cbSSangeeta Misra 	return (ret);
350*dbed73cbSSangeeta Misra }
351*dbed73cbSSangeeta Misra 
352*dbed73cbSSangeeta Misra /*
353*dbed73cbSSangeeta Misra  * Given a hc object name, return its information.  Used by libilb to
354*dbed73cbSSangeeta Misra  * get hc info.
355*dbed73cbSSangeeta Misra  */
356*dbed73cbSSangeeta Misra ilb_status_t
357*dbed73cbSSangeeta Misra ilbd_get_hc_info(const char *hc_name, uint32_t *rbuf, size_t *rbufsz)
358*dbed73cbSSangeeta Misra {
359*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
360*dbed73cbSSangeeta Misra 	ilb_hc_info_t	*hc_info;
361*dbed73cbSSangeeta Misra 	ilb_comm_t	*ic = (ilb_comm_t *)rbuf;
362*dbed73cbSSangeeta Misra 
363*dbed73cbSSangeeta Misra 	hc = ilbd_get_hc(hc_name);
364*dbed73cbSSangeeta Misra 	if (hc == NULL) {
365*dbed73cbSSangeeta Misra 		logdebug("%s: healthcheck %s does not exist", __func__,
366*dbed73cbSSangeeta Misra 		    hc_name);
367*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
368*dbed73cbSSangeeta Misra 	}
369*dbed73cbSSangeeta Misra 	ilbd_reply_ok(rbuf, rbufsz);
370*dbed73cbSSangeeta Misra 	hc_info = (ilb_hc_info_t *)&ic->ic_data;
371*dbed73cbSSangeeta Misra 
372*dbed73cbSSangeeta Misra 	(void) strlcpy(hc_info->hci_name, hc->ihc_name, sizeof (hc->ihc_name));
373*dbed73cbSSangeeta Misra 	(void) strlcpy(hc_info->hci_test, hc->ihc_test, sizeof (hc->ihc_test));
374*dbed73cbSSangeeta Misra 	hc_info->hci_timeout = hc->ihc_timeout;
375*dbed73cbSSangeeta Misra 	hc_info->hci_count = hc->ihc_count;
376*dbed73cbSSangeeta Misra 	hc_info->hci_interval = hc->ihc_interval;
377*dbed73cbSSangeeta Misra 	hc_info->hci_def_ping = hc->ihc_def_ping;
378*dbed73cbSSangeeta Misra 
379*dbed73cbSSangeeta Misra 	*rbufsz += sizeof (ilb_hc_info_t);
380*dbed73cbSSangeeta Misra 
381*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
382*dbed73cbSSangeeta Misra }
383*dbed73cbSSangeeta Misra 
384*dbed73cbSSangeeta Misra static void
385*dbed73cbSSangeeta Misra ilbd_hc_copy_srvs(uint32_t *rbuf, size_t *rbufsz, ilbd_hc_rule_t *hc_rule,
386*dbed73cbSSangeeta Misra     const char *rulename)
387*dbed73cbSSangeeta Misra {
388*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t		*tmp_srv;
389*dbed73cbSSangeeta Misra 	ilb_hc_srv_t		*dst_srv;
390*dbed73cbSSangeeta Misra 	ilb_hc_rule_srv_t	*srvs;
391*dbed73cbSSangeeta Misra 	size_t			tmp_rbufsz;
392*dbed73cbSSangeeta Misra 	int			i;
393*dbed73cbSSangeeta Misra 
394*dbed73cbSSangeeta Misra 	tmp_rbufsz = *rbufsz;
395*dbed73cbSSangeeta Misra 	/* Set up the reply buffer.  rbufsz will be set to the new size. */
396*dbed73cbSSangeeta Misra 	ilbd_reply_ok(rbuf, rbufsz);
397*dbed73cbSSangeeta Misra 
398*dbed73cbSSangeeta Misra 	/* Calculate how much space is left for holding server info. */
399*dbed73cbSSangeeta Misra 	*rbufsz += sizeof (ilb_hc_rule_srv_t);
400*dbed73cbSSangeeta Misra 	tmp_rbufsz -= *rbufsz;
401*dbed73cbSSangeeta Misra 
402*dbed73cbSSangeeta Misra 	srvs = (ilb_hc_rule_srv_t *)&((ilb_comm_t *)rbuf)->ic_data;
403*dbed73cbSSangeeta Misra 
404*dbed73cbSSangeeta Misra 	tmp_srv = list_head(&hc_rule->hcr_servers);
405*dbed73cbSSangeeta Misra 	for (i = 0; tmp_srv != NULL && tmp_rbufsz >= sizeof (*dst_srv); i++) {
406*dbed73cbSSangeeta Misra 		dst_srv = &srvs->rs_srvs[i];
407*dbed73cbSSangeeta Misra 
408*dbed73cbSSangeeta Misra 		(void) strlcpy(dst_srv->hcs_rule_name, rulename, ILB_NAMESZ);
409*dbed73cbSSangeeta Misra 		(void) strlcpy(dst_srv->hcs_ID, tmp_srv->shc_sg_srv->sgs_srvID,
410*dbed73cbSSangeeta Misra 		    ILB_NAMESZ);
411*dbed73cbSSangeeta Misra 		(void) strlcpy(dst_srv->hcs_hc_name,
412*dbed73cbSSangeeta Misra 		    tmp_srv->shc_hc->ihc_name, ILB_NAMESZ);
413*dbed73cbSSangeeta Misra 		dst_srv->hcs_IP = tmp_srv->shc_sg_srv->sgs_addr;
414*dbed73cbSSangeeta Misra 		dst_srv->hcs_fail_cnt = tmp_srv->shc_fail_cnt;
415*dbed73cbSSangeeta Misra 		dst_srv->hcs_status = tmp_srv->shc_status;
416*dbed73cbSSangeeta Misra 		dst_srv->hcs_rtt = tmp_srv->shc_rtt;
417*dbed73cbSSangeeta Misra 		dst_srv->hcs_lasttime = tmp_srv->shc_lasttime;
418*dbed73cbSSangeeta Misra 		dst_srv->hcs_nexttime = tmp_srv->shc_nexttime;
419*dbed73cbSSangeeta Misra 
420*dbed73cbSSangeeta Misra 		tmp_srv = list_next(&hc_rule->hcr_servers, tmp_srv);
421*dbed73cbSSangeeta Misra 		tmp_rbufsz -= sizeof (*dst_srv);
422*dbed73cbSSangeeta Misra 	}
423*dbed73cbSSangeeta Misra 	srvs->rs_num_srvs = i;
424*dbed73cbSSangeeta Misra 	*rbufsz += i * sizeof (*dst_srv);
425*dbed73cbSSangeeta Misra }
426*dbed73cbSSangeeta Misra 
427*dbed73cbSSangeeta Misra /*
428*dbed73cbSSangeeta Misra  * Given a rule name, return the hc status of its servers.
429*dbed73cbSSangeeta Misra  */
430*dbed73cbSSangeeta Misra ilb_status_t
431*dbed73cbSSangeeta Misra ilbd_get_hc_srvs(const char *rulename, uint32_t *rbuf, size_t *rbufsz)
432*dbed73cbSSangeeta Misra {
433*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
434*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
435*dbed73cbSSangeeta Misra 
436*dbed73cbSSangeeta Misra 	for (hc = list_head(&ilbd_hc_list); hc != NULL;
437*dbed73cbSSangeeta Misra 	    hc = list_next(&ilbd_hc_list, hc)) {
438*dbed73cbSSangeeta Misra 		for (hc_rule = list_head(&hc->ihc_rules); hc_rule != NULL;
439*dbed73cbSSangeeta Misra 		    hc_rule = list_next(&hc->ihc_rules, hc_rule)) {
440*dbed73cbSSangeeta Misra 			if (strcasecmp(hc_rule->hcr_rule->irl_name,
441*dbed73cbSSangeeta Misra 			    rulename) != 0) {
442*dbed73cbSSangeeta Misra 				continue;
443*dbed73cbSSangeeta Misra 			}
444*dbed73cbSSangeeta Misra 			ilbd_hc_copy_srvs(rbuf, rbufsz, hc_rule, rulename);
445*dbed73cbSSangeeta Misra 			return (ILB_STATUS_OK);
446*dbed73cbSSangeeta Misra 		}
447*dbed73cbSSangeeta Misra 	}
448*dbed73cbSSangeeta Misra 	return (ILB_STATUS_RULE_NO_HC);
449*dbed73cbSSangeeta Misra }
450*dbed73cbSSangeeta Misra 
451*dbed73cbSSangeeta Misra /*
452*dbed73cbSSangeeta Misra  * Initialize the hc timer and associate the notification of timeout to
453*dbed73cbSSangeeta Misra  * the given event port.
454*dbed73cbSSangeeta Misra  */
455*dbed73cbSSangeeta Misra void
456*dbed73cbSSangeeta Misra ilbd_hc_timer_init(int ev_port, ilbd_timer_event_obj_t *ev_obj)
457*dbed73cbSSangeeta Misra {
458*dbed73cbSSangeeta Misra 	struct sigevent sigev;
459*dbed73cbSSangeeta Misra 	port_notify_t notify;
460*dbed73cbSSangeeta Misra 
461*dbed73cbSSangeeta Misra 	if ((ilbd_hc_timer_q = iu_tq_create()) == NULL) {
462*dbed73cbSSangeeta Misra 		logerr("%s: cannot create hc timer queue", __func__);
463*dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
464*dbed73cbSSangeeta Misra 	}
465*dbed73cbSSangeeta Misra 	hc_timer_restarted = B_FALSE;
466*dbed73cbSSangeeta Misra 
467*dbed73cbSSangeeta Misra 	ev_obj->ev = ILBD_EVENT_TIMER;
468*dbed73cbSSangeeta Misra 	ev_obj->timerid = -1;
469*dbed73cbSSangeeta Misra 
470*dbed73cbSSangeeta Misra 	notify.portnfy_port = ev_port;
471*dbed73cbSSangeeta Misra 	notify.portnfy_user = ev_obj;
472*dbed73cbSSangeeta Misra 	sigev.sigev_notify = SIGEV_PORT;
473*dbed73cbSSangeeta Misra 	sigev.sigev_value.sival_ptr = &notify;
474*dbed73cbSSangeeta Misra 	if (timer_create(CLOCK_REALTIME, &sigev, &ev_obj->timerid) == -1) {
475*dbed73cbSSangeeta Misra 		logerr("%s: cannot create timer", __func__);
476*dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
477*dbed73cbSSangeeta Misra 	}
478*dbed73cbSSangeeta Misra }
479*dbed73cbSSangeeta Misra 
480*dbed73cbSSangeeta Misra /*
481*dbed73cbSSangeeta Misra  * HC timeout handler.
482*dbed73cbSSangeeta Misra  */
483*dbed73cbSSangeeta Misra void
484*dbed73cbSSangeeta Misra ilbd_hc_timeout(void)
485*dbed73cbSSangeeta Misra {
486*dbed73cbSSangeeta Misra 	(void) iu_expire_timers(ilbd_hc_timer_q);
487*dbed73cbSSangeeta Misra 	hc_timer_restarted = B_TRUE;
488*dbed73cbSSangeeta Misra }
489*dbed73cbSSangeeta Misra 
490*dbed73cbSSangeeta Misra /*
491*dbed73cbSSangeeta Misra  * Set up the timer to fire at the earliest timeout.
492*dbed73cbSSangeeta Misra  */
493*dbed73cbSSangeeta Misra void
494*dbed73cbSSangeeta Misra ilbd_hc_timer_update(ilbd_timer_event_obj_t *ev_obj)
495*dbed73cbSSangeeta Misra {
496*dbed73cbSSangeeta Misra 	itimerspec_t itimeout;
497*dbed73cbSSangeeta Misra 	int timeout;
498*dbed73cbSSangeeta Misra 
499*dbed73cbSSangeeta Misra 	/*
500*dbed73cbSSangeeta Misra 	 * There is no change on the timer list, so no need to set up the
501*dbed73cbSSangeeta Misra 	 * timer again.
502*dbed73cbSSangeeta Misra 	 */
503*dbed73cbSSangeeta Misra 	if (!hc_timer_restarted)
504*dbed73cbSSangeeta Misra 		return;
505*dbed73cbSSangeeta Misra 
506*dbed73cbSSangeeta Misra restart:
507*dbed73cbSSangeeta Misra 	if ((timeout = iu_earliest_timer(ilbd_hc_timer_q)) == INFTIM) {
508*dbed73cbSSangeeta Misra 		hc_timer_restarted = B_FALSE;
509*dbed73cbSSangeeta Misra 		return;
510*dbed73cbSSangeeta Misra 	} else if (timeout == 0) {
511*dbed73cbSSangeeta Misra 		/*
512*dbed73cbSSangeeta Misra 		 * Handle the timeout immediately.  After that (clearing all
513*dbed73cbSSangeeta Misra 		 * the expired timers), check to  see if there are still
514*dbed73cbSSangeeta Misra 		 * timers running.  If yes, start them.
515*dbed73cbSSangeeta Misra 		 */
516*dbed73cbSSangeeta Misra 		(void) iu_expire_timers(ilbd_hc_timer_q);
517*dbed73cbSSangeeta Misra 		goto restart;
518*dbed73cbSSangeeta Misra 	}
519*dbed73cbSSangeeta Misra 
520*dbed73cbSSangeeta Misra 	itimeout.it_value.tv_sec = timeout / MILLISEC + 1;
521*dbed73cbSSangeeta Misra 	itimeout.it_value.tv_nsec = 0;
522*dbed73cbSSangeeta Misra 	itimeout.it_interval.tv_sec = 0;
523*dbed73cbSSangeeta Misra 	itimeout.it_interval.tv_nsec = 0;
524*dbed73cbSSangeeta Misra 
525*dbed73cbSSangeeta Misra 	/*
526*dbed73cbSSangeeta Misra 	 * Failure to set a timeout is "OK" since hopefully there will be
527*dbed73cbSSangeeta Misra 	 * other events and timer_settime() will be called again.  So
528*dbed73cbSSangeeta Misra 	 * we will only miss some timeouts.  But in the worst case, no event
529*dbed73cbSSangeeta Misra 	 * will happen and ilbd will get stuck...
530*dbed73cbSSangeeta Misra 	 */
531*dbed73cbSSangeeta Misra 	if (timer_settime(ev_obj->timerid, 0, &itimeout, NULL) == -1)
532*dbed73cbSSangeeta Misra 		logerr("%s: cannot set timer", __func__);
533*dbed73cbSSangeeta Misra 	hc_timer_restarted = B_FALSE;
534*dbed73cbSSangeeta Misra }
535*dbed73cbSSangeeta Misra 
536*dbed73cbSSangeeta Misra /*
537*dbed73cbSSangeeta Misra  * Kill the probe process of a server.
538*dbed73cbSSangeeta Misra  */
539*dbed73cbSSangeeta Misra static void
540*dbed73cbSSangeeta Misra ilbd_hc_kill_probe(ilbd_hc_srv_t *srv)
541*dbed73cbSSangeeta Misra {
542*dbed73cbSSangeeta Misra 	/*
543*dbed73cbSSangeeta Misra 	 * First dissociate the fd from the event port.  It should not
544*dbed73cbSSangeeta Misra 	 * fail.
545*dbed73cbSSangeeta Misra 	 */
546*dbed73cbSSangeeta Misra 	if (port_dissociate(srv->shc_ev_port, PORT_SOURCE_FD,
547*dbed73cbSSangeeta Misra 	    srv->shc_child_fd) != 0) {
548*dbed73cbSSangeeta Misra 		logdebug("%s: port_dissociate: %s", __func__, strerror(errno));
549*dbed73cbSSangeeta Misra 	}
550*dbed73cbSSangeeta Misra 	(void) close(srv->shc_child_fd);
551*dbed73cbSSangeeta Misra 	free(srv->shc_ev);
552*dbed73cbSSangeeta Misra 	srv->shc_ev = NULL;
553*dbed73cbSSangeeta Misra 
554*dbed73cbSSangeeta Misra 	/* Then kill the probe process. */
555*dbed73cbSSangeeta Misra 	if (kill(srv->shc_child_pid, SIGKILL) != 0) {
556*dbed73cbSSangeeta Misra 		logerr("%s: rule %s server %s: %s", __func__,
557*dbed73cbSSangeeta Misra 		    srv->shc_hc_rule->hcr_rule->irl_name,
558*dbed73cbSSangeeta Misra 		    srv->shc_sg_srv->sgs_srvID, strerror(errno));
559*dbed73cbSSangeeta Misra 	}
560*dbed73cbSSangeeta Misra 	/* Should not fail... */
561*dbed73cbSSangeeta Misra 	if (waitpid(srv->shc_child_pid, NULL, 0) != srv->shc_child_pid) {
562*dbed73cbSSangeeta Misra 		logdebug("%s: waitpid: rule %s server %s", __func__,
563*dbed73cbSSangeeta Misra 		    srv->shc_hc_rule->hcr_rule->irl_name,
564*dbed73cbSSangeeta Misra 		    srv->shc_sg_srv->sgs_srvID);
565*dbed73cbSSangeeta Misra 	}
566*dbed73cbSSangeeta Misra 	srv->shc_child_pid = 0;
567*dbed73cbSSangeeta Misra }
568*dbed73cbSSangeeta Misra 
569*dbed73cbSSangeeta Misra /*
570*dbed73cbSSangeeta Misra  * Disable the server, either because the server is dead or because a timer
571*dbed73cbSSangeeta Misra  * cannot be started for this server.  Note that this only affects the
572*dbed73cbSSangeeta Misra  * transient configuration, meaning only in memory.  The persistent
573*dbed73cbSSangeeta Misra  * configuration is not affected.
574*dbed73cbSSangeeta Misra  */
575*dbed73cbSSangeeta Misra static void
576*dbed73cbSSangeeta Misra ilbd_mark_server_disabled(ilbd_hc_srv_t *srv)
577*dbed73cbSSangeeta Misra {
578*dbed73cbSSangeeta Misra 	srv->shc_status = ILB_HCS_DISABLED;
579*dbed73cbSSangeeta Misra 
580*dbed73cbSSangeeta Misra 	/* Disable the server in kernel. */
581*dbed73cbSSangeeta Misra 	if (ilbd_k_Xable_server(&srv->shc_sg_srv->sgs_addr,
582*dbed73cbSSangeeta Misra 	    srv->shc_hc_rule->hcr_rule->irl_name,
583*dbed73cbSSangeeta Misra 	    stat_declare_srv_dead) != ILB_STATUS_OK) {
584*dbed73cbSSangeeta Misra 		logerr("%s: cannot disable server in kernel: rule %s "
585*dbed73cbSSangeeta Misra 		    "server %s", __func__,
586*dbed73cbSSangeeta Misra 		    srv->shc_hc_rule->hcr_rule->irl_name,
587*dbed73cbSSangeeta Misra 		    srv->shc_sg_srv->sgs_srvID);
588*dbed73cbSSangeeta Misra 	}
589*dbed73cbSSangeeta Misra }
590*dbed73cbSSangeeta Misra 
591*dbed73cbSSangeeta Misra /*
592*dbed73cbSSangeeta Misra  * A probe fails, set the state of the server.
593*dbed73cbSSangeeta Misra  */
594*dbed73cbSSangeeta Misra static void
595*dbed73cbSSangeeta Misra ilbd_set_fail_state(ilbd_hc_srv_t *srv)
596*dbed73cbSSangeeta Misra {
597*dbed73cbSSangeeta Misra 	if (++srv->shc_fail_cnt < srv->shc_hc->ihc_count) {
598*dbed73cbSSangeeta Misra 		/* Probe again */
599*dbed73cbSSangeeta Misra 		ilbd_hc_probe_timer(ilbd_hc_timer_q, srv);
600*dbed73cbSSangeeta Misra 		return;
601*dbed73cbSSangeeta Misra 	}
602*dbed73cbSSangeeta Misra 
603*dbed73cbSSangeeta Misra 	logdebug("%s: rule %s server %s fails %u", __func__,
604*dbed73cbSSangeeta Misra 	    srv->shc_hc_rule->hcr_rule->irl_name, srv->shc_sg_srv->sgs_srvID,
605*dbed73cbSSangeeta Misra 	    srv->shc_fail_cnt);
606*dbed73cbSSangeeta Misra 
607*dbed73cbSSangeeta Misra 	/*
608*dbed73cbSSangeeta Misra 	 * If this is a ping test, mark the server as
609*dbed73cbSSangeeta Misra 	 * unreachable instead of dead.
610*dbed73cbSSangeeta Misra 	 */
611*dbed73cbSSangeeta Misra 	if (srv->shc_hc->ihc_test_type == ILBD_HC_PING ||
612*dbed73cbSSangeeta Misra 	    srv->shc_state == ilbd_hc_def_pinging) {
613*dbed73cbSSangeeta Misra 		srv->shc_status = ILB_HCS_UNREACH;
614*dbed73cbSSangeeta Misra 	} else {
615*dbed73cbSSangeeta Misra 		srv->shc_status = ILB_HCS_DEAD;
616*dbed73cbSSangeeta Misra 	}
617*dbed73cbSSangeeta Misra 
618*dbed73cbSSangeeta Misra 	/* Disable the server in kernel. */
619*dbed73cbSSangeeta Misra 	if (ilbd_k_Xable_server(&srv->shc_sg_srv->sgs_addr,
620*dbed73cbSSangeeta Misra 	    srv->shc_hc_rule->hcr_rule->irl_name, stat_declare_srv_dead) !=
621*dbed73cbSSangeeta Misra 	    ILB_STATUS_OK) {
622*dbed73cbSSangeeta Misra 		logerr("%s: cannot disable server in kernel: rule %s "
623*dbed73cbSSangeeta Misra 		    "server %s", __func__,
624*dbed73cbSSangeeta Misra 		    srv->shc_hc_rule->hcr_rule->irl_name,
625*dbed73cbSSangeeta Misra 		    srv->shc_sg_srv->sgs_srvID);
626*dbed73cbSSangeeta Misra 	}
627*dbed73cbSSangeeta Misra 
628*dbed73cbSSangeeta Misra 	/* Still keep probing in case the server is alive again. */
629*dbed73cbSSangeeta Misra 	if (ilbd_hc_restart_timer(srv->shc_hc, srv) != ILB_STATUS_OK) {
630*dbed73cbSSangeeta Misra 		/* Only thing to do is to disable the server... */
631*dbed73cbSSangeeta Misra 		logerr("%s: cannot restart timer: rule %s server %s", __func__,
632*dbed73cbSSangeeta Misra 		    srv->shc_hc_rule->hcr_rule->irl_name,
633*dbed73cbSSangeeta Misra 		    srv->shc_sg_srv->sgs_srvID);
634*dbed73cbSSangeeta Misra 		srv->shc_status = ILB_HCS_DISABLED;
635*dbed73cbSSangeeta Misra 	}
636*dbed73cbSSangeeta Misra }
637*dbed73cbSSangeeta Misra 
638*dbed73cbSSangeeta Misra /*
639*dbed73cbSSangeeta Misra  * A probe process has not returned for the ihc_timeout period, we should
640*dbed73cbSSangeeta Misra  * kill it.  This function is the handler of this.
641*dbed73cbSSangeeta Misra  */
642*dbed73cbSSangeeta Misra /* ARGSUSED */
643*dbed73cbSSangeeta Misra static void
644*dbed73cbSSangeeta Misra ilbd_hc_kill_timer(iu_tq_t *tq, void *arg)
645*dbed73cbSSangeeta Misra {
646*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *srv = (ilbd_hc_srv_t *)arg;
647*dbed73cbSSangeeta Misra 
648*dbed73cbSSangeeta Misra 	ilbd_hc_kill_probe(srv);
649*dbed73cbSSangeeta Misra 	ilbd_set_fail_state(srv);
650*dbed73cbSSangeeta Misra }
651*dbed73cbSSangeeta Misra 
652*dbed73cbSSangeeta Misra /*
653*dbed73cbSSangeeta Misra  * Probe timeout handler.  Send out the appropriate probe.
654*dbed73cbSSangeeta Misra  */
655*dbed73cbSSangeeta Misra /* ARGSUSED */
656*dbed73cbSSangeeta Misra static void
657*dbed73cbSSangeeta Misra ilbd_hc_probe_timer(iu_tq_t *tq, void *arg)
658*dbed73cbSSangeeta Misra {
659*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *srv = (ilbd_hc_srv_t *)arg;
660*dbed73cbSSangeeta Misra 
661*dbed73cbSSangeeta Misra 	/*
662*dbed73cbSSangeeta Misra 	 * If starting the probe fails, just pretend that the timeout has
663*dbed73cbSSangeeta Misra 	 * extended.
664*dbed73cbSSangeeta Misra 	 */
665*dbed73cbSSangeeta Misra 	if (!ilbd_run_probe(srv)) {
666*dbed73cbSSangeeta Misra 		/*
667*dbed73cbSSangeeta Misra 		 * If we cannot restart the timer, the only thing we can do
668*dbed73cbSSangeeta Misra 		 * is to disable this server.  Hopefully the sys admin will
669*dbed73cbSSangeeta Misra 		 * notice this and enable this server again later.
670*dbed73cbSSangeeta Misra 		 */
671*dbed73cbSSangeeta Misra 		if (ilbd_hc_restart_timer(srv->shc_hc, srv) != ILB_STATUS_OK) {
672*dbed73cbSSangeeta Misra 			logerr("%s: cannot restart timer: rule %s server %s, "
673*dbed73cbSSangeeta Misra 			    "disabling it", __func__,
674*dbed73cbSSangeeta Misra 			    srv->shc_hc_rule->hcr_rule->irl_name,
675*dbed73cbSSangeeta Misra 			    srv->shc_sg_srv->sgs_srvID);
676*dbed73cbSSangeeta Misra 			ilbd_mark_server_disabled(srv);
677*dbed73cbSSangeeta Misra 		}
678*dbed73cbSSangeeta Misra 		return;
679*dbed73cbSSangeeta Misra 	}
680*dbed73cbSSangeeta Misra 
681*dbed73cbSSangeeta Misra 	/*
682*dbed73cbSSangeeta Misra 	 * Similar to above, if kill timer cannot be started, disable the
683*dbed73cbSSangeeta Misra 	 * server.
684*dbed73cbSSangeeta Misra 	 */
685*dbed73cbSSangeeta Misra 	if ((srv->shc_tid = iu_schedule_timer(ilbd_hc_timer_q,
686*dbed73cbSSangeeta Misra 	    srv->shc_hc->ihc_timeout, ilbd_hc_kill_timer, srv)) == -1) {
687*dbed73cbSSangeeta Misra 		logerr("%s: cannot start kill timer: rule %s server %s, "
688*dbed73cbSSangeeta Misra 		    "disabling it", __func__,
689*dbed73cbSSangeeta Misra 		    srv->shc_hc_rule->hcr_rule->irl_name,
690*dbed73cbSSangeeta Misra 		    srv->shc_sg_srv->sgs_srvID);
691*dbed73cbSSangeeta Misra 		ilbd_mark_server_disabled(srv);
692*dbed73cbSSangeeta Misra 	}
693*dbed73cbSSangeeta Misra 	hc_timer_restarted = B_TRUE;
694*dbed73cbSSangeeta Misra }
695*dbed73cbSSangeeta Misra 
696*dbed73cbSSangeeta Misra /* Restart the periodic timer for a given server. */
697*dbed73cbSSangeeta Misra static ilb_status_t
698*dbed73cbSSangeeta Misra ilbd_hc_restart_timer(ilbd_hc_t *hc, ilbd_hc_srv_t *srv)
699*dbed73cbSSangeeta Misra {
700*dbed73cbSSangeeta Misra 	int timeout;
701*dbed73cbSSangeeta Misra 
702*dbed73cbSSangeeta Misra 	/* Don't allow the timeout interval to be less than 1s */
703*dbed73cbSSangeeta Misra 	timeout = MAX((hc->ihc_interval >> 1) + (gethrtime() %
704*dbed73cbSSangeeta Misra 	    (hc->ihc_interval + 1)), 1);
705*dbed73cbSSangeeta Misra 
706*dbed73cbSSangeeta Misra 	/*
707*dbed73cbSSangeeta Misra 	 * If the probe is actually a ping probe, there is no need to
708*dbed73cbSSangeeta Misra 	 * do default pinging.  Just skip the step.
709*dbed73cbSSangeeta Misra 	 */
710*dbed73cbSSangeeta Misra 	if (hc->ihc_def_ping && hc->ihc_test_type != ILBD_HC_PING)
711*dbed73cbSSangeeta Misra 		srv->shc_state = ilbd_hc_def_pinging;
712*dbed73cbSSangeeta Misra 	else
713*dbed73cbSSangeeta Misra 		srv->shc_state = ilbd_hc_probing;
714*dbed73cbSSangeeta Misra 	srv->shc_tid = iu_schedule_timer(ilbd_hc_timer_q, timeout,
715*dbed73cbSSangeeta Misra 	    ilbd_hc_probe_timer, srv);
716*dbed73cbSSangeeta Misra 
717*dbed73cbSSangeeta Misra 	if (srv->shc_tid == -1)
718*dbed73cbSSangeeta Misra 		return (ILB_STATUS_TIMER);
719*dbed73cbSSangeeta Misra 	srv->shc_lasttime = time(NULL);
720*dbed73cbSSangeeta Misra 	srv->shc_nexttime = time(NULL) + timeout;
721*dbed73cbSSangeeta Misra 
722*dbed73cbSSangeeta Misra 	hc_timer_restarted = B_TRUE;
723*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
724*dbed73cbSSangeeta Misra }
725*dbed73cbSSangeeta Misra 
726*dbed73cbSSangeeta Misra /* Helper routine to associate a server with its hc object. */
727*dbed73cbSSangeeta Misra static ilb_status_t
728*dbed73cbSSangeeta Misra ilbd_hc_srv_add(ilbd_hc_t *hc, ilbd_hc_rule_t *hc_rule,
729*dbed73cbSSangeeta Misra     const ilb_sg_srv_t *srv, int ev_port)
730*dbed73cbSSangeeta Misra {
731*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *new_srv;
732*dbed73cbSSangeeta Misra 	ilb_status_t ret;
733*dbed73cbSSangeeta Misra 
734*dbed73cbSSangeeta Misra 	if ((new_srv = calloc(1, sizeof (ilbd_hc_srv_t))) == NULL)
735*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
736*dbed73cbSSangeeta Misra 	new_srv->shc_hc = hc;
737*dbed73cbSSangeeta Misra 	new_srv->shc_hc_rule = hc_rule;
738*dbed73cbSSangeeta Misra 	new_srv->shc_sg_srv = srv;
739*dbed73cbSSangeeta Misra 	new_srv->shc_ev_port = ev_port;
740*dbed73cbSSangeeta Misra 	new_srv->shc_tid = -1;
741*dbed73cbSSangeeta Misra 	new_srv->shc_nexttime = time(NULL);
742*dbed73cbSSangeeta Misra 	new_srv->shc_lasttime = new_srv->shc_nexttime;
743*dbed73cbSSangeeta Misra 
744*dbed73cbSSangeeta Misra 	if ((hc_rule->hcr_rule->irl_flags & ILB_FLAGS_RULE_ENABLED) &&
745*dbed73cbSSangeeta Misra 	    ILB_IS_SRV_ENABLED(srv->sgs_flags)) {
746*dbed73cbSSangeeta Misra 		new_srv->shc_status = ILB_HCS_UNINIT;
747*dbed73cbSSangeeta Misra 		ret = ilbd_hc_restart_timer(hc, new_srv);
748*dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK) {
749*dbed73cbSSangeeta Misra 			free(new_srv);
750*dbed73cbSSangeeta Misra 			return (ret);
751*dbed73cbSSangeeta Misra 		}
752*dbed73cbSSangeeta Misra 	} else {
753*dbed73cbSSangeeta Misra 		new_srv->shc_status = ILB_HCS_DISABLED;
754*dbed73cbSSangeeta Misra 	}
755*dbed73cbSSangeeta Misra 
756*dbed73cbSSangeeta Misra 	list_insert_tail(&hc_rule->hcr_servers, new_srv);
757*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
758*dbed73cbSSangeeta Misra }
759*dbed73cbSSangeeta Misra 
760*dbed73cbSSangeeta Misra /* Handy macro to cancel a server's timer. */
761*dbed73cbSSangeeta Misra #define	HC_CANCEL_TIMER(srv)						\
762*dbed73cbSSangeeta Misra {									\
763*dbed73cbSSangeeta Misra 	void *arg;							\
764*dbed73cbSSangeeta Misra 	int ret;							\
765*dbed73cbSSangeeta Misra 	if ((srv)->shc_tid != -1) {					\
766*dbed73cbSSangeeta Misra 		ret = iu_cancel_timer(ilbd_hc_timer_q, (srv)->shc_tid, &arg); \
767*dbed73cbSSangeeta Misra 		(srv)->shc_tid = -1;					\
768*dbed73cbSSangeeta Misra 		assert(ret == 1);					\
769*dbed73cbSSangeeta Misra 		assert(arg == (srv));					\
770*dbed73cbSSangeeta Misra 	}								\
771*dbed73cbSSangeeta Misra 	hc_timer_restarted = B_TRUE;					\
772*dbed73cbSSangeeta Misra }
773*dbed73cbSSangeeta Misra 
774*dbed73cbSSangeeta Misra /* Helper routine to dissociate a server from its hc object. */
775*dbed73cbSSangeeta Misra static ilb_status_t
776*dbed73cbSSangeeta Misra ilbd_hc_srv_rem(ilbd_hc_rule_t *hc_rule, const ilb_sg_srv_t *srv)
777*dbed73cbSSangeeta Misra {
778*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *tmp_srv;
779*dbed73cbSSangeeta Misra 
780*dbed73cbSSangeeta Misra 	for (tmp_srv = list_head(&hc_rule->hcr_servers); tmp_srv != NULL;
781*dbed73cbSSangeeta Misra 	    tmp_srv = list_next(&hc_rule->hcr_servers, tmp_srv)) {
782*dbed73cbSSangeeta Misra 		if (tmp_srv->shc_sg_srv == srv) {
783*dbed73cbSSangeeta Misra 			list_remove(&hc_rule->hcr_servers, tmp_srv);
784*dbed73cbSSangeeta Misra 			HC_CANCEL_TIMER(tmp_srv);
785*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_child_pid != 0)
786*dbed73cbSSangeeta Misra 				ilbd_hc_kill_probe(tmp_srv);
787*dbed73cbSSangeeta Misra 			free(tmp_srv);
788*dbed73cbSSangeeta Misra 			return (ILB_STATUS_OK);
789*dbed73cbSSangeeta Misra 		}
790*dbed73cbSSangeeta Misra 	}
791*dbed73cbSSangeeta Misra 	return (ILB_STATUS_ENOENT);
792*dbed73cbSSangeeta Misra }
793*dbed73cbSSangeeta Misra 
794*dbed73cbSSangeeta Misra /* Helper routine to dissociate all servers of a rule from its hc object. */
795*dbed73cbSSangeeta Misra static void
796*dbed73cbSSangeeta Misra ilbd_hc_srv_rem_all(ilbd_hc_rule_t *hc_rule)
797*dbed73cbSSangeeta Misra {
798*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *srv;
799*dbed73cbSSangeeta Misra 
800*dbed73cbSSangeeta Misra 	while ((srv = list_remove_head(&hc_rule->hcr_servers)) != NULL) {
801*dbed73cbSSangeeta Misra 		HC_CANCEL_TIMER(srv);
802*dbed73cbSSangeeta Misra 		if (srv->shc_child_pid != 0)
803*dbed73cbSSangeeta Misra 			ilbd_hc_kill_probe(srv);
804*dbed73cbSSangeeta Misra 		free(srv);
805*dbed73cbSSangeeta Misra 	}
806*dbed73cbSSangeeta Misra }
807*dbed73cbSSangeeta Misra 
808*dbed73cbSSangeeta Misra /* Associate a rule with its hc object. */
809*dbed73cbSSangeeta Misra ilb_status_t
810*dbed73cbSSangeeta Misra ilbd_hc_associate_rule(const ilbd_rule_t *rule, int ev_port)
811*dbed73cbSSangeeta Misra {
812*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
813*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
814*dbed73cbSSangeeta Misra 	ilb_status_t	ret;
815*dbed73cbSSangeeta Misra 	ilbd_sg_t	*sg;
816*dbed73cbSSangeeta Misra 	ilbd_srv_t	*ilbd_srv;
817*dbed73cbSSangeeta Misra 
818*dbed73cbSSangeeta Misra 	/* The rule is assumed to be initialized appropriately. */
819*dbed73cbSSangeeta Misra 	if ((hc = ilbd_get_hc(rule->irl_hcname)) == NULL) {
820*dbed73cbSSangeeta Misra 		logdebug("ilbd_hc_associate_rule: healthcheck %s does not "
821*dbed73cbSSangeeta Misra 		    "exist", rule->irl_hcname);
822*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOHCINFO);
823*dbed73cbSSangeeta Misra 	}
824*dbed73cbSSangeeta Misra 	if ((hc->ihc_test_type == ILBD_HC_TCP &&
825*dbed73cbSSangeeta Misra 	    rule->irl_proto != IPPROTO_TCP) ||
826*dbed73cbSSangeeta Misra 	    (hc->ihc_test_type == ILBD_HC_UDP &&
827*dbed73cbSSangeeta Misra 	    rule->irl_proto != IPPROTO_UDP)) {
828*dbed73cbSSangeeta Misra 		return (ILB_STATUS_RULE_HC_MISMATCH);
829*dbed73cbSSangeeta Misra 	}
830*dbed73cbSSangeeta Misra 	if ((hc_rule = calloc(1, sizeof (ilbd_hc_rule_t))) == NULL) {
831*dbed73cbSSangeeta Misra 		logdebug("ilbd_hc_associate_rule: out of memory");
832*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
833*dbed73cbSSangeeta Misra 	}
834*dbed73cbSSangeeta Misra 
835*dbed73cbSSangeeta Misra 	hc_rule->hcr_rule = rule;
836*dbed73cbSSangeeta Misra 	list_create(&hc_rule->hcr_servers, sizeof (ilbd_hc_srv_t),
837*dbed73cbSSangeeta Misra 	    offsetof(ilbd_hc_srv_t, shc_srv_link));
838*dbed73cbSSangeeta Misra 
839*dbed73cbSSangeeta Misra 	/* Add all the servers. */
840*dbed73cbSSangeeta Misra 	sg = rule->irl_sg;
841*dbed73cbSSangeeta Misra 	for (ilbd_srv = list_head(&sg->isg_srvlist); ilbd_srv != NULL;
842*dbed73cbSSangeeta Misra 	    ilbd_srv = list_next(&sg->isg_srvlist, ilbd_srv)) {
843*dbed73cbSSangeeta Misra 		if ((ret = ilbd_hc_srv_add(hc, hc_rule, &ilbd_srv->isv_srv,
844*dbed73cbSSangeeta Misra 		    ev_port)) != ILB_STATUS_OK) {
845*dbed73cbSSangeeta Misra 			/* Remove all previously added servers */
846*dbed73cbSSangeeta Misra 			ilbd_hc_srv_rem_all(hc_rule);
847*dbed73cbSSangeeta Misra 			free(hc_rule);
848*dbed73cbSSangeeta Misra 			return (ret);
849*dbed73cbSSangeeta Misra 		}
850*dbed73cbSSangeeta Misra 	}
851*dbed73cbSSangeeta Misra 	list_insert_tail(&hc->ihc_rules, hc_rule);
852*dbed73cbSSangeeta Misra 	hc->ihc_rule_cnt++;
853*dbed73cbSSangeeta Misra 
854*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
855*dbed73cbSSangeeta Misra }
856*dbed73cbSSangeeta Misra 
857*dbed73cbSSangeeta Misra /* Dissociate a rule from its hc object. */
858*dbed73cbSSangeeta Misra ilb_status_t
859*dbed73cbSSangeeta Misra ilbd_hc_dissociate_rule(const ilbd_rule_t *rule)
860*dbed73cbSSangeeta Misra {
861*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
862*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
863*dbed73cbSSangeeta Misra 
864*dbed73cbSSangeeta Misra 	/* The rule is assumed to be initialized appropriately. */
865*dbed73cbSSangeeta Misra 	if ((hc = ilbd_get_hc(rule->irl_hcname)) == NULL) {
866*dbed73cbSSangeeta Misra 		logdebug("ilbd_hc_dissociate_rule: healthcheck %s does not "
867*dbed73cbSSangeeta Misra 		    "exist", rule->irl_hcname);
868*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
869*dbed73cbSSangeeta Misra 	}
870*dbed73cbSSangeeta Misra 	for (hc_rule = list_head(&hc->ihc_rules); hc_rule != NULL;
871*dbed73cbSSangeeta Misra 	    hc_rule = list_next(&hc->ihc_rules, hc_rule)) {
872*dbed73cbSSangeeta Misra 		if (hc_rule->hcr_rule == rule)
873*dbed73cbSSangeeta Misra 			break;
874*dbed73cbSSangeeta Misra 	}
875*dbed73cbSSangeeta Misra 	if (hc_rule == NULL) {
876*dbed73cbSSangeeta Misra 		logdebug("ilbd_hc_dissociate_rule: rule %s is not associated "
877*dbed73cbSSangeeta Misra 		    "with healtcheck %s", rule->irl_hcname, hc->ihc_name);
878*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
879*dbed73cbSSangeeta Misra 	}
880*dbed73cbSSangeeta Misra 	ilbd_hc_srv_rem_all(hc_rule);
881*dbed73cbSSangeeta Misra 	list_remove(&hc->ihc_rules, hc_rule);
882*dbed73cbSSangeeta Misra 	hc->ihc_rule_cnt--;
883*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
884*dbed73cbSSangeeta Misra }
885*dbed73cbSSangeeta Misra 
886*dbed73cbSSangeeta Misra /*
887*dbed73cbSSangeeta Misra  * Given a hc object name and a rule, check to see if the rule is associated
888*dbed73cbSSangeeta Misra  * with the hc object.  If it is, the hc object is returned in **hc and the
889*dbed73cbSSangeeta Misra  * ilbd_hc_rule_t is returned in **hc_rule.
890*dbed73cbSSangeeta Misra  */
891*dbed73cbSSangeeta Misra static boolean_t
892*dbed73cbSSangeeta Misra ilbd_hc_check_rule(const char *hc_name, const ilbd_rule_t *rule,
893*dbed73cbSSangeeta Misra     ilbd_hc_t **hc, ilbd_hc_rule_t **hc_rule)
894*dbed73cbSSangeeta Misra {
895*dbed73cbSSangeeta Misra 	ilbd_hc_t	*tmp_hc;
896*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*tmp_hc_rule;
897*dbed73cbSSangeeta Misra 
898*dbed73cbSSangeeta Misra 	if ((tmp_hc = ilbd_get_hc(hc_name)) == NULL)
899*dbed73cbSSangeeta Misra 		return (B_FALSE);
900*dbed73cbSSangeeta Misra 	for (tmp_hc_rule = list_head(&tmp_hc->ihc_rules); tmp_hc_rule != NULL;
901*dbed73cbSSangeeta Misra 	    tmp_hc_rule = list_next(&tmp_hc->ihc_rules, tmp_hc_rule)) {
902*dbed73cbSSangeeta Misra 		if (tmp_hc_rule->hcr_rule == rule) {
903*dbed73cbSSangeeta Misra 			*hc = tmp_hc;
904*dbed73cbSSangeeta Misra 			*hc_rule = tmp_hc_rule;
905*dbed73cbSSangeeta Misra 			return (B_TRUE);
906*dbed73cbSSangeeta Misra 		}
907*dbed73cbSSangeeta Misra 	}
908*dbed73cbSSangeeta Misra 	return (B_FALSE);
909*dbed73cbSSangeeta Misra }
910*dbed73cbSSangeeta Misra 
911*dbed73cbSSangeeta Misra /* Associate a server with its hc object. */
912*dbed73cbSSangeeta Misra ilb_status_t
913*dbed73cbSSangeeta Misra ilbd_hc_add_server(const ilbd_rule_t *rule, const ilb_sg_srv_t *srv,
914*dbed73cbSSangeeta Misra     int ev_port)
915*dbed73cbSSangeeta Misra {
916*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
917*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
918*dbed73cbSSangeeta Misra 
919*dbed73cbSSangeeta Misra 	if (!ilbd_hc_check_rule(rule->irl_hcname, rule, &hc, &hc_rule))
920*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
921*dbed73cbSSangeeta Misra 	return (ilbd_hc_srv_add(hc, hc_rule, srv, ev_port));
922*dbed73cbSSangeeta Misra }
923*dbed73cbSSangeeta Misra 
924*dbed73cbSSangeeta Misra /* Dissociate a server from its hc object. */
925*dbed73cbSSangeeta Misra ilb_status_t
926*dbed73cbSSangeeta Misra ilbd_hc_del_server(const ilbd_rule_t *rule, const ilb_sg_srv_t *srv)
927*dbed73cbSSangeeta Misra {
928*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
929*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
930*dbed73cbSSangeeta Misra 
931*dbed73cbSSangeeta Misra 	if (!ilbd_hc_check_rule(rule->irl_hcname, rule, &hc, &hc_rule))
932*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
933*dbed73cbSSangeeta Misra 	return (ilbd_hc_srv_rem(hc_rule, srv));
934*dbed73cbSSangeeta Misra }
935*dbed73cbSSangeeta Misra 
936*dbed73cbSSangeeta Misra /* Helper routine to enable/disable a server's hc probe. */
937*dbed73cbSSangeeta Misra static ilb_status_t
938*dbed73cbSSangeeta Misra ilbd_hc_toggle_server(const ilbd_rule_t *rule, const ilb_sg_srv_t *srv,
939*dbed73cbSSangeeta Misra     boolean_t enable)
940*dbed73cbSSangeeta Misra {
941*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
942*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
943*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t	*tmp_srv;
944*dbed73cbSSangeeta Misra 	ilb_status_t	ret;
945*dbed73cbSSangeeta Misra 
946*dbed73cbSSangeeta Misra 	if (!ilbd_hc_check_rule(rule->irl_hcname, rule, &hc, &hc_rule))
947*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
948*dbed73cbSSangeeta Misra 	for (tmp_srv = list_head(&hc_rule->hcr_servers); tmp_srv != NULL;
949*dbed73cbSSangeeta Misra 	    tmp_srv = list_next(&hc_rule->hcr_servers, tmp_srv)) {
950*dbed73cbSSangeeta Misra 		if (tmp_srv->shc_sg_srv != srv) {
951*dbed73cbSSangeeta Misra 			continue;
952*dbed73cbSSangeeta Misra 		}
953*dbed73cbSSangeeta Misra 		if (enable) {
954*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_status == ILB_HCS_DISABLED) {
955*dbed73cbSSangeeta Misra 				ret = ilbd_hc_restart_timer(hc, tmp_srv);
956*dbed73cbSSangeeta Misra 				if (ret != ILB_STATUS_OK) {
957*dbed73cbSSangeeta Misra 					logerr("%s: cannot start timers for "
958*dbed73cbSSangeeta Misra 					    "rule %s server %s", __func__,
959*dbed73cbSSangeeta Misra 					    rule->irl_name,
960*dbed73cbSSangeeta Misra 					    tmp_srv->shc_sg_srv->sgs_srvID);
961*dbed73cbSSangeeta Misra 					return (ret);
962*dbed73cbSSangeeta Misra 				}
963*dbed73cbSSangeeta Misra 				/* Start from fresh... */
964*dbed73cbSSangeeta Misra 				tmp_srv->shc_status = ILB_HCS_UNINIT;
965*dbed73cbSSangeeta Misra 				tmp_srv->shc_rtt = 0;
966*dbed73cbSSangeeta Misra 				tmp_srv->shc_fail_cnt = 0;
967*dbed73cbSSangeeta Misra 			}
968*dbed73cbSSangeeta Misra 		} else {
969*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_status != ILB_HCS_DISABLED) {
970*dbed73cbSSangeeta Misra 				tmp_srv->shc_status = ILB_HCS_DISABLED;
971*dbed73cbSSangeeta Misra 				HC_CANCEL_TIMER(tmp_srv);
972*dbed73cbSSangeeta Misra 				if (tmp_srv->shc_child_pid != 0)
973*dbed73cbSSangeeta Misra 					ilbd_hc_kill_probe(tmp_srv);
974*dbed73cbSSangeeta Misra 			}
975*dbed73cbSSangeeta Misra 		}
976*dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
977*dbed73cbSSangeeta Misra 	}
978*dbed73cbSSangeeta Misra 	return (ILB_STATUS_ENOENT);
979*dbed73cbSSangeeta Misra }
980*dbed73cbSSangeeta Misra 
981*dbed73cbSSangeeta Misra ilb_status_t
982*dbed73cbSSangeeta Misra ilbd_hc_enable_server(const ilbd_rule_t *rule, const ilb_sg_srv_t *srv)
983*dbed73cbSSangeeta Misra {
984*dbed73cbSSangeeta Misra 	return (ilbd_hc_toggle_server(rule, srv, B_TRUE));
985*dbed73cbSSangeeta Misra }
986*dbed73cbSSangeeta Misra 
987*dbed73cbSSangeeta Misra ilb_status_t
988*dbed73cbSSangeeta Misra ilbd_hc_disable_server(const ilbd_rule_t *rule, const ilb_sg_srv_t *srv)
989*dbed73cbSSangeeta Misra {
990*dbed73cbSSangeeta Misra 	return (ilbd_hc_toggle_server(rule, srv, B_FALSE));
991*dbed73cbSSangeeta Misra }
992*dbed73cbSSangeeta Misra 
993*dbed73cbSSangeeta Misra /*
994*dbed73cbSSangeeta Misra  * Helper routine to enable/disable a rule's hc probe (including all its
995*dbed73cbSSangeeta Misra  * servers).
996*dbed73cbSSangeeta Misra  */
997*dbed73cbSSangeeta Misra static ilb_status_t
998*dbed73cbSSangeeta Misra ilbd_hc_toggle_rule(const ilbd_rule_t *rule, boolean_t enable)
999*dbed73cbSSangeeta Misra {
1000*dbed73cbSSangeeta Misra 	ilbd_hc_t	*hc;
1001*dbed73cbSSangeeta Misra 	ilbd_hc_rule_t	*hc_rule;
1002*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t	*tmp_srv;
1003*dbed73cbSSangeeta Misra 	int		ret;
1004*dbed73cbSSangeeta Misra 
1005*dbed73cbSSangeeta Misra 	if (!ilbd_hc_check_rule(rule->irl_hcname, rule, &hc, &hc_rule))
1006*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
1007*dbed73cbSSangeeta Misra 
1008*dbed73cbSSangeeta Misra 	for (tmp_srv = list_head(&hc_rule->hcr_servers); tmp_srv != NULL;
1009*dbed73cbSSangeeta Misra 	    tmp_srv = list_next(&hc_rule->hcr_servers, tmp_srv)) {
1010*dbed73cbSSangeeta Misra 		if (enable) {
1011*dbed73cbSSangeeta Misra 			/*
1012*dbed73cbSSangeeta Misra 			 * If the server is disabled in the rule, do not
1013*dbed73cbSSangeeta Misra 			 * restart its timer.
1014*dbed73cbSSangeeta Misra 			 */
1015*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_status == ILB_HCS_DISABLED &&
1016*dbed73cbSSangeeta Misra 			    ILB_IS_SRV_ENABLED(
1017*dbed73cbSSangeeta Misra 			    tmp_srv->shc_sg_srv->sgs_flags)) {
1018*dbed73cbSSangeeta Misra 				ret = ilbd_hc_restart_timer(hc, tmp_srv);
1019*dbed73cbSSangeeta Misra 				if (ret != ILB_STATUS_OK) {
1020*dbed73cbSSangeeta Misra 					logerr("%s: cannot start timers for "
1021*dbed73cbSSangeeta Misra 					    "rule %s server %s", __func__,
1022*dbed73cbSSangeeta Misra 					    rule->irl_name,
1023*dbed73cbSSangeeta Misra 					    tmp_srv->shc_sg_srv->sgs_srvID);
1024*dbed73cbSSangeeta Misra 					goto rollback;
1025*dbed73cbSSangeeta Misra 				} else {
1026*dbed73cbSSangeeta Misra 					/* Start from fresh... */
1027*dbed73cbSSangeeta Misra 					tmp_srv->shc_status = ILB_HCS_UNINIT;
1028*dbed73cbSSangeeta Misra 					tmp_srv->shc_rtt = 0;
1029*dbed73cbSSangeeta Misra 					tmp_srv->shc_fail_cnt = 0;
1030*dbed73cbSSangeeta Misra 				}
1031*dbed73cbSSangeeta Misra 			}
1032*dbed73cbSSangeeta Misra 		} else {
1033*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_status != ILB_HCS_DISABLED) {
1034*dbed73cbSSangeeta Misra 				HC_CANCEL_TIMER(tmp_srv);
1035*dbed73cbSSangeeta Misra 				tmp_srv->shc_status = ILB_HCS_DISABLED;
1036*dbed73cbSSangeeta Misra 				if (tmp_srv->shc_child_pid != 0)
1037*dbed73cbSSangeeta Misra 					ilbd_hc_kill_probe(tmp_srv);
1038*dbed73cbSSangeeta Misra 			}
1039*dbed73cbSSangeeta Misra 		}
1040*dbed73cbSSangeeta Misra 	}
1041*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
1042*dbed73cbSSangeeta Misra rollback:
1043*dbed73cbSSangeeta Misra 	enable = !enable;
1044*dbed73cbSSangeeta Misra 	for (tmp_srv = list_prev(&hc_rule->hcr_servers, tmp_srv);
1045*dbed73cbSSangeeta Misra 	    tmp_srv != NULL;
1046*dbed73cbSSangeeta Misra 	    tmp_srv = list_prev(&hc_rule->hcr_servers, tmp_srv)) {
1047*dbed73cbSSangeeta Misra 		if (enable) {
1048*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_status == ILB_HCS_DISABLED &&
1049*dbed73cbSSangeeta Misra 			    ILB_IS_SRV_ENABLED(
1050*dbed73cbSSangeeta Misra 			    tmp_srv->shc_sg_srv->sgs_flags)) {
1051*dbed73cbSSangeeta Misra 				(void) ilbd_hc_restart_timer(hc, tmp_srv);
1052*dbed73cbSSangeeta Misra 				tmp_srv->shc_status = ILB_HCS_UNINIT;
1053*dbed73cbSSangeeta Misra 				tmp_srv->shc_rtt = 0;
1054*dbed73cbSSangeeta Misra 				tmp_srv->shc_fail_cnt = 0;
1055*dbed73cbSSangeeta Misra 			}
1056*dbed73cbSSangeeta Misra 		} else {
1057*dbed73cbSSangeeta Misra 			if (tmp_srv->shc_status != ILB_HCS_DISABLED) {
1058*dbed73cbSSangeeta Misra 				HC_CANCEL_TIMER(tmp_srv);
1059*dbed73cbSSangeeta Misra 				tmp_srv->shc_status = ILB_HCS_DISABLED;
1060*dbed73cbSSangeeta Misra 				if (tmp_srv->shc_child_pid != 0)
1061*dbed73cbSSangeeta Misra 					ilbd_hc_kill_probe(tmp_srv);
1062*dbed73cbSSangeeta Misra 			}
1063*dbed73cbSSangeeta Misra 		}
1064*dbed73cbSSangeeta Misra 	}
1065*dbed73cbSSangeeta Misra 	return (ret);
1066*dbed73cbSSangeeta Misra }
1067*dbed73cbSSangeeta Misra 
1068*dbed73cbSSangeeta Misra ilb_status_t
1069*dbed73cbSSangeeta Misra ilbd_hc_enable_rule(const ilbd_rule_t *rule)
1070*dbed73cbSSangeeta Misra {
1071*dbed73cbSSangeeta Misra 	return (ilbd_hc_toggle_rule(rule, B_TRUE));
1072*dbed73cbSSangeeta Misra }
1073*dbed73cbSSangeeta Misra 
1074*dbed73cbSSangeeta Misra ilb_status_t
1075*dbed73cbSSangeeta Misra ilbd_hc_disable_rule(const ilbd_rule_t *rule)
1076*dbed73cbSSangeeta Misra {
1077*dbed73cbSSangeeta Misra 	return (ilbd_hc_toggle_rule(rule, B_FALSE));
1078*dbed73cbSSangeeta Misra }
1079*dbed73cbSSangeeta Misra 
1080*dbed73cbSSangeeta Misra static const char *
1081*dbed73cbSSangeeta Misra topo_2_str(ilb_topo_t topo)
1082*dbed73cbSSangeeta Misra {
1083*dbed73cbSSangeeta Misra 	switch (topo) {
1084*dbed73cbSSangeeta Misra 	case ILB_TOPO_DSR:
1085*dbed73cbSSangeeta Misra 		return ("DSR");
1086*dbed73cbSSangeeta Misra 		break;
1087*dbed73cbSSangeeta Misra 	case ILB_TOPO_NAT:
1088*dbed73cbSSangeeta Misra 		return ("NAT");
1089*dbed73cbSSangeeta Misra 		break;
1090*dbed73cbSSangeeta Misra 	case ILB_TOPO_HALF_NAT:
1091*dbed73cbSSangeeta Misra 		return ("HALF_NAT");
1092*dbed73cbSSangeeta Misra 		break;
1093*dbed73cbSSangeeta Misra 	default:
1094*dbed73cbSSangeeta Misra 		/* Should not happen. */
1095*dbed73cbSSangeeta Misra 		logerr("%s: unknown topology", __func__);
1096*dbed73cbSSangeeta Misra 		break;
1097*dbed73cbSSangeeta Misra 	}
1098*dbed73cbSSangeeta Misra 	return ("");
1099*dbed73cbSSangeeta Misra }
1100*dbed73cbSSangeeta Misra 
1101*dbed73cbSSangeeta Misra /*
1102*dbed73cbSSangeeta Misra  * Create the argument list to be passed to a hc probe command.
1103*dbed73cbSSangeeta Misra  * The passed in argv is assumed to have HC_PROBE_ARGC elements.
1104*dbed73cbSSangeeta Misra  */
1105*dbed73cbSSangeeta Misra static boolean_t
1106*dbed73cbSSangeeta Misra create_argv(ilbd_hc_srv_t *srv, char *argv[])
1107*dbed73cbSSangeeta Misra {
1108*dbed73cbSSangeeta Misra 	char buf[INET6_ADDRSTRLEN];
1109*dbed73cbSSangeeta Misra 	ilbd_rule_t const *rule;
1110*dbed73cbSSangeeta Misra 	ilb_sg_srv_t const *sg_srv;
1111*dbed73cbSSangeeta Misra 	struct in_addr v4_addr;
1112*dbed73cbSSangeeta Misra 	in_port_t port;
1113*dbed73cbSSangeeta Misra 	int i;
1114*dbed73cbSSangeeta Misra 
1115*dbed73cbSSangeeta Misra 	rule = srv->shc_hc_rule->hcr_rule;
1116*dbed73cbSSangeeta Misra 	sg_srv = srv->shc_sg_srv;
1117*dbed73cbSSangeeta Misra 
1118*dbed73cbSSangeeta Misra 	if (srv->shc_state == ilbd_hc_def_pinging) {
1119*dbed73cbSSangeeta Misra 		if ((argv[0] = strdup(ILB_PROBE_PING)) == NULL)
1120*dbed73cbSSangeeta Misra 			return (B_FALSE);
1121*dbed73cbSSangeeta Misra 	} else {
1122*dbed73cbSSangeeta Misra 		switch (srv->shc_hc->ihc_test_type) {
1123*dbed73cbSSangeeta Misra 		case ILBD_HC_USER:
1124*dbed73cbSSangeeta Misra 			if ((argv[0] = strdup(srv->shc_hc->ihc_test)) == NULL)
1125*dbed73cbSSangeeta Misra 				return (B_FALSE);
1126*dbed73cbSSangeeta Misra 			break;
1127*dbed73cbSSangeeta Misra 		case ILBD_HC_TCP:
1128*dbed73cbSSangeeta Misra 		case ILBD_HC_UDP:
1129*dbed73cbSSangeeta Misra 			if ((argv[0] = strdup(ILB_PROBE_PROTO)) ==
1130*dbed73cbSSangeeta Misra 			    NULL) {
1131*dbed73cbSSangeeta Misra 				return (B_FALSE);
1132*dbed73cbSSangeeta Misra 			}
1133*dbed73cbSSangeeta Misra 			break;
1134*dbed73cbSSangeeta Misra 		case ILBD_HC_PING:
1135*dbed73cbSSangeeta Misra 			if ((argv[0] = strdup(ILB_PROBE_PING)) == NULL) {
1136*dbed73cbSSangeeta Misra 				return (B_FALSE);
1137*dbed73cbSSangeeta Misra 			}
1138*dbed73cbSSangeeta Misra 			break;
1139*dbed73cbSSangeeta Misra 		}
1140*dbed73cbSSangeeta Misra 	}
1141*dbed73cbSSangeeta Misra 
1142*dbed73cbSSangeeta Misra 	/*
1143*dbed73cbSSangeeta Misra 	 * argv[1] is the VIP.
1144*dbed73cbSSangeeta Misra 	 *
1145*dbed73cbSSangeeta Misra 	 * Right now, the VIP and the backend server addresses should be
1146*dbed73cbSSangeeta Misra 	 * in the same IP address family.  Here we don't do that in case
1147*dbed73cbSSangeeta Misra 	 * this assumption is changed in future.
1148*dbed73cbSSangeeta Misra 	 */
1149*dbed73cbSSangeeta Misra 	if (IN6_IS_ADDR_V4MAPPED(&rule->irl_vip)) {
1150*dbed73cbSSangeeta Misra 		IN6_V4MAPPED_TO_INADDR(&rule->irl_vip, &v4_addr);
1151*dbed73cbSSangeeta Misra 		if (inet_ntop(AF_INET, &v4_addr, buf, sizeof (buf)) == NULL)
1152*dbed73cbSSangeeta Misra 			goto cleanup;
1153*dbed73cbSSangeeta Misra 	} else {
1154*dbed73cbSSangeeta Misra 		if (inet_ntop(AF_INET6, &rule->irl_vip, buf,
1155*dbed73cbSSangeeta Misra 		    sizeof (buf)) == NULL) {
1156*dbed73cbSSangeeta Misra 			goto cleanup;
1157*dbed73cbSSangeeta Misra 		}
1158*dbed73cbSSangeeta Misra 	}
1159*dbed73cbSSangeeta Misra 	if ((argv[1] = strdup(buf)) == NULL)
1160*dbed73cbSSangeeta Misra 		goto cleanup;
1161*dbed73cbSSangeeta Misra 
1162*dbed73cbSSangeeta Misra 	/*
1163*dbed73cbSSangeeta Misra 	 * argv[2] is the backend server address.
1164*dbed73cbSSangeeta Misra 	 */
1165*dbed73cbSSangeeta Misra 	if (IN6_IS_ADDR_V4MAPPED(&sg_srv->sgs_addr)) {
1166*dbed73cbSSangeeta Misra 		IN6_V4MAPPED_TO_INADDR(&sg_srv->sgs_addr, &v4_addr);
1167*dbed73cbSSangeeta Misra 		if (inet_ntop(AF_INET, &v4_addr, buf, sizeof (buf)) == NULL)
1168*dbed73cbSSangeeta Misra 			goto cleanup;
1169*dbed73cbSSangeeta Misra 	} else {
1170*dbed73cbSSangeeta Misra 		if (inet_ntop(AF_INET6, &sg_srv->sgs_addr, buf,
1171*dbed73cbSSangeeta Misra 		    sizeof (buf)) == NULL) {
1172*dbed73cbSSangeeta Misra 			goto cleanup;
1173*dbed73cbSSangeeta Misra 		}
1174*dbed73cbSSangeeta Misra 	}
1175*dbed73cbSSangeeta Misra 	if ((argv[2] = strdup(buf)) == NULL)
1176*dbed73cbSSangeeta Misra 		goto cleanup;
1177*dbed73cbSSangeeta Misra 
1178*dbed73cbSSangeeta Misra 	/*
1179*dbed73cbSSangeeta Misra 	 * argv[3] is the transport protocol used in the rule.
1180*dbed73cbSSangeeta Misra 	 */
1181*dbed73cbSSangeeta Misra 	switch (rule->irl_proto) {
1182*dbed73cbSSangeeta Misra 	case IPPROTO_TCP:
1183*dbed73cbSSangeeta Misra 		argv[3] = strdup("TCP");
1184*dbed73cbSSangeeta Misra 		break;
1185*dbed73cbSSangeeta Misra 	case IPPROTO_UDP:
1186*dbed73cbSSangeeta Misra 		argv[3] = strdup("UDP");
1187*dbed73cbSSangeeta Misra 		break;
1188*dbed73cbSSangeeta Misra 	default:
1189*dbed73cbSSangeeta Misra 		logerr("%s: unknown protocol", __func__);
1190*dbed73cbSSangeeta Misra 		goto cleanup;
1191*dbed73cbSSangeeta Misra 		break;
1192*dbed73cbSSangeeta Misra 	}
1193*dbed73cbSSangeeta Misra 	if (argv[3] == NULL)
1194*dbed73cbSSangeeta Misra 		goto cleanup;
1195*dbed73cbSSangeeta Misra 
1196*dbed73cbSSangeeta Misra 	/*
1197*dbed73cbSSangeeta Misra 	 * argv[4] is the load balance mode, DSR, NAT, HALF-NAT.
1198*dbed73cbSSangeeta Misra 	 */
1199*dbed73cbSSangeeta Misra 	if ((argv[4] = strdup(topo_2_str(rule->irl_topo))) == NULL)
1200*dbed73cbSSangeeta Misra 		goto cleanup;
1201*dbed73cbSSangeeta Misra 
1202*dbed73cbSSangeeta Misra 	/*
1203*dbed73cbSSangeeta Misra 	 * argv[5] is the port range.  Right now, there should only be 1 port.
1204*dbed73cbSSangeeta Misra 	 */
1205*dbed73cbSSangeeta Misra 	switch (rule->irl_hcpflag) {
1206*dbed73cbSSangeeta Misra 	case ILB_HCI_PROBE_FIX:
1207*dbed73cbSSangeeta Misra 		port = ntohs(rule->irl_hcport);
1208*dbed73cbSSangeeta Misra 		break;
1209*dbed73cbSSangeeta Misra 	case ILB_HCI_PROBE_ANY: {
1210*dbed73cbSSangeeta Misra 		in_port_t min, max;
1211*dbed73cbSSangeeta Misra 
1212*dbed73cbSSangeeta Misra 		if (ntohs(sg_srv->sgs_minport) == 0) {
1213*dbed73cbSSangeeta Misra 			min = ntohs(rule->irl_minport);
1214*dbed73cbSSangeeta Misra 			max = ntohs(rule->irl_maxport);
1215*dbed73cbSSangeeta Misra 		} else {
1216*dbed73cbSSangeeta Misra 			min = ntohs(sg_srv->sgs_minport);
1217*dbed73cbSSangeeta Misra 			max = ntohs(sg_srv->sgs_maxport);
1218*dbed73cbSSangeeta Misra 		}
1219*dbed73cbSSangeeta Misra 		if (max > min)
1220*dbed73cbSSangeeta Misra 			port = min + gethrtime() % (max - min + 1);
1221*dbed73cbSSangeeta Misra 		else
1222*dbed73cbSSangeeta Misra 			port = min;
1223*dbed73cbSSangeeta Misra 		break;
1224*dbed73cbSSangeeta Misra 	}
1225*dbed73cbSSangeeta Misra 	default:
1226*dbed73cbSSangeeta Misra 		logerr("%s: unknown HC flag", __func__);
1227*dbed73cbSSangeeta Misra 		goto cleanup;
1228*dbed73cbSSangeeta Misra 		break;
1229*dbed73cbSSangeeta Misra 	}
1230*dbed73cbSSangeeta Misra 	(void) sprintf(buf, "%d", port);
1231*dbed73cbSSangeeta Misra 	if ((argv[5] = strdup(buf)) == NULL)
1232*dbed73cbSSangeeta Misra 		goto cleanup;
1233*dbed73cbSSangeeta Misra 
1234*dbed73cbSSangeeta Misra 	/*
1235*dbed73cbSSangeeta Misra 	 * argv[6] is the probe timeout.
1236*dbed73cbSSangeeta Misra 	 */
1237*dbed73cbSSangeeta Misra 	(void) sprintf(buf, "%d", srv->shc_hc->ihc_timeout);
1238*dbed73cbSSangeeta Misra 	if ((argv[6] = strdup(buf)) == NULL)
1239*dbed73cbSSangeeta Misra 		goto cleanup;
1240*dbed73cbSSangeeta Misra 
1241*dbed73cbSSangeeta Misra 	argv[7] = NULL;
1242*dbed73cbSSangeeta Misra 	return (B_TRUE);
1243*dbed73cbSSangeeta Misra 
1244*dbed73cbSSangeeta Misra cleanup:
1245*dbed73cbSSangeeta Misra 	for (i = 0; i < HC_PROBE_ARGC; i++) {
1246*dbed73cbSSangeeta Misra 		if (argv[i] != NULL)
1247*dbed73cbSSangeeta Misra 			free(argv[i]);
1248*dbed73cbSSangeeta Misra 	}
1249*dbed73cbSSangeeta Misra 	return (B_FALSE);
1250*dbed73cbSSangeeta Misra }
1251*dbed73cbSSangeeta Misra 
1252*dbed73cbSSangeeta Misra static void
1253*dbed73cbSSangeeta Misra destroy_argv(char *argv[])
1254*dbed73cbSSangeeta Misra {
1255*dbed73cbSSangeeta Misra 	int i;
1256*dbed73cbSSangeeta Misra 
1257*dbed73cbSSangeeta Misra 	for (i = 0; argv[i] != NULL; i++)
1258*dbed73cbSSangeeta Misra 		free(argv[i]);
1259*dbed73cbSSangeeta Misra }
1260*dbed73cbSSangeeta Misra 
1261*dbed73cbSSangeeta Misra /* Spawn a process to run the hc probe on the given server. */
1262*dbed73cbSSangeeta Misra static boolean_t
1263*dbed73cbSSangeeta Misra ilbd_run_probe(ilbd_hc_srv_t *srv)
1264*dbed73cbSSangeeta Misra {
1265*dbed73cbSSangeeta Misra 	posix_spawn_file_actions_t	fd_actions;
1266*dbed73cbSSangeeta Misra 	posix_spawnattr_t		attr;
1267*dbed73cbSSangeeta Misra 	sigset_t			child_sigset;
1268*dbed73cbSSangeeta Misra 	int				fds[2];
1269*dbed73cbSSangeeta Misra 	int				fdflags;
1270*dbed73cbSSangeeta Misra 	pid_t				pid;
1271*dbed73cbSSangeeta Misra 	char				*child_argv[HC_PROBE_ARGC];
1272*dbed73cbSSangeeta Misra 	ilbd_hc_probe_event_t		*probe_ev;
1273*dbed73cbSSangeeta Misra 	char				*probe_name;
1274*dbed73cbSSangeeta Misra 
1275*dbed73cbSSangeeta Misra 	bzero(child_argv, HC_PROBE_ARGC * sizeof (char *));
1276*dbed73cbSSangeeta Misra 	if ((probe_ev = calloc(1, sizeof (*probe_ev))) == NULL) {
1277*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: calloc");
1278*dbed73cbSSangeeta Misra 		return (B_FALSE);
1279*dbed73cbSSangeeta Misra 	}
1280*dbed73cbSSangeeta Misra 
1281*dbed73cbSSangeeta Misra 	/* Set up a pipe to get output from probe command. */
1282*dbed73cbSSangeeta Misra 	if (pipe(fds) < 0) {
1283*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: cannot create pipe");
1284*dbed73cbSSangeeta Misra 		free(probe_ev);
1285*dbed73cbSSangeeta Misra 		return (B_FALSE);
1286*dbed73cbSSangeeta Misra 	}
1287*dbed73cbSSangeeta Misra 	/* Set our side of the pipe to be non-blocking */
1288*dbed73cbSSangeeta Misra 	if ((fdflags = fcntl(fds[0], F_GETFL, 0)) == -1) {
1289*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: fcntl(F_GETFL)");
1290*dbed73cbSSangeeta Misra 		goto cleanup;
1291*dbed73cbSSangeeta Misra 	}
1292*dbed73cbSSangeeta Misra 	if (fcntl(fds[0], F_SETFL, fdflags | O_NONBLOCK) == -1) {
1293*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: fcntl(F_SETFL)");
1294*dbed73cbSSangeeta Misra 		goto cleanup;
1295*dbed73cbSSangeeta Misra 	}
1296*dbed73cbSSangeeta Misra 
1297*dbed73cbSSangeeta Misra 	if (posix_spawn_file_actions_init(&fd_actions) != 0) {
1298*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawn_file_actions_init");
1299*dbed73cbSSangeeta Misra 		goto cleanup;
1300*dbed73cbSSangeeta Misra 	}
1301*dbed73cbSSangeeta Misra 	if (posix_spawnattr_init(&attr) != 0) {
1302*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawnattr_init");
1303*dbed73cbSSangeeta Misra 		goto cleanup;
1304*dbed73cbSSangeeta Misra 	}
1305*dbed73cbSSangeeta Misra 	if (posix_spawn_file_actions_addclose(&fd_actions, fds[0]) != 0) {
1306*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawn_file_actions_addclose");
1307*dbed73cbSSangeeta Misra 		goto cleanup;
1308*dbed73cbSSangeeta Misra 	}
1309*dbed73cbSSangeeta Misra 	if (posix_spawn_file_actions_adddup2(&fd_actions, fds[1],
1310*dbed73cbSSangeeta Misra 	    STDOUT_FILENO) != 0) {
1311*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawn_file_actions_dup2");
1312*dbed73cbSSangeeta Misra 		goto cleanup;
1313*dbed73cbSSangeeta Misra 	}
1314*dbed73cbSSangeeta Misra 	if (posix_spawn_file_actions_addclose(&fd_actions, fds[1]) != 0) {
1315*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawn_file_actions_addclose");
1316*dbed73cbSSangeeta Misra 		goto cleanup;
1317*dbed73cbSSangeeta Misra 	}
1318*dbed73cbSSangeeta Misra 
1319*dbed73cbSSangeeta Misra 	/* Reset all signal handling of the child to default. */
1320*dbed73cbSSangeeta Misra 	(void) sigfillset(&child_sigset);
1321*dbed73cbSSangeeta Misra 	if (posix_spawnattr_setsigdefault(&attr, &child_sigset) != 0) {
1322*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawnattr_setsigdefault");
1323*dbed73cbSSangeeta Misra 		goto cleanup;
1324*dbed73cbSSangeeta Misra 	}
1325*dbed73cbSSangeeta Misra 	/* Don't want SIGCHLD. */
1326*dbed73cbSSangeeta Misra 	if (posix_spawnattr_setflags(&attr, POSIX_SPAWN_NOSIGCHLD_NP|
1327*dbed73cbSSangeeta Misra 	    POSIX_SPAWN_SETSIGDEF) != 0) {
1328*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: posix_spawnattr_setflags");
1329*dbed73cbSSangeeta Misra 		goto cleanup;
1330*dbed73cbSSangeeta Misra 	}
1331*dbed73cbSSangeeta Misra 
1332*dbed73cbSSangeeta Misra 	if (!create_argv(srv, child_argv)) {
1333*dbed73cbSSangeeta Misra 		logdebug("ilbd_run_probe: create_argv");
1334*dbed73cbSSangeeta Misra 		goto cleanup;
1335*dbed73cbSSangeeta Misra 	}
1336*dbed73cbSSangeeta Misra 
1337*dbed73cbSSangeeta Misra 	/*
1338*dbed73cbSSangeeta Misra 	 * If we are doing default pinging or not using a user supplied
1339*dbed73cbSSangeeta Misra 	 * probe, we should execute our standard supplied probe.  The
1340*dbed73cbSSangeeta Misra 	 * supplied probe command handles all types of probes.  And the
1341*dbed73cbSSangeeta Misra 	 * type used depends on argv[0], as filled in by create_argv().
1342*dbed73cbSSangeeta Misra 	 */
1343*dbed73cbSSangeeta Misra 	if (srv->shc_state == ilbd_hc_def_pinging ||
1344*dbed73cbSSangeeta Misra 	    srv->shc_hc->ihc_test_type != ILBD_HC_USER) {
1345*dbed73cbSSangeeta Misra 		probe_name = ILB_PROBE_PROTO;
1346*dbed73cbSSangeeta Misra 	} else {
1347*dbed73cbSSangeeta Misra 		probe_name = srv->shc_hc->ihc_test;
1348*dbed73cbSSangeeta Misra 	}
1349*dbed73cbSSangeeta Misra 	if (posix_spawn(&pid, probe_name, &fd_actions, &attr, child_argv,
1350*dbed73cbSSangeeta Misra 	    NULL) != 0) {
1351*dbed73cbSSangeeta Misra 		logerr("%s: posix_spawn: %s for server %s: %s", __func__,
1352*dbed73cbSSangeeta Misra 		    srv->shc_hc->ihc_test, srv->shc_sg_srv->sgs_srvID,
1353*dbed73cbSSangeeta Misra 		    strerror(errno));
1354*dbed73cbSSangeeta Misra 		goto cleanup;
1355*dbed73cbSSangeeta Misra 	}
1356*dbed73cbSSangeeta Misra 
1357*dbed73cbSSangeeta Misra 	(void) close(fds[1]);
1358*dbed73cbSSangeeta Misra 	destroy_argv(child_argv);
1359*dbed73cbSSangeeta Misra 	srv->shc_child_pid = pid;
1360*dbed73cbSSangeeta Misra 	srv->shc_child_fd = fds[0];
1361*dbed73cbSSangeeta Misra 	srv->shc_ev = probe_ev;
1362*dbed73cbSSangeeta Misra 
1363*dbed73cbSSangeeta Misra 	probe_ev->ihp_ev = ILBD_EVENT_PROBE;
1364*dbed73cbSSangeeta Misra 	probe_ev->ihp_srv = srv;
1365*dbed73cbSSangeeta Misra 	probe_ev->ihp_pid = pid;
1366*dbed73cbSSangeeta Misra 	if (port_associate(srv->shc_ev_port, PORT_SOURCE_FD, fds[0],
1367*dbed73cbSSangeeta Misra 	    POLLRDNORM, probe_ev) != 0) {
1368*dbed73cbSSangeeta Misra 		/*
1369*dbed73cbSSangeeta Misra 		 * Need to kill the child.  It will free the srv->shc_ev,
1370*dbed73cbSSangeeta Misra 		 * which is probe_ev.  So set probe_ev to NULL.
1371*dbed73cbSSangeeta Misra 		 */
1372*dbed73cbSSangeeta Misra 		ilbd_hc_kill_probe(srv);
1373*dbed73cbSSangeeta Misra 		probe_ev = NULL;
1374*dbed73cbSSangeeta Misra 		goto cleanup;
1375*dbed73cbSSangeeta Misra 	}
1376*dbed73cbSSangeeta Misra 
1377*dbed73cbSSangeeta Misra 	return (B_TRUE);
1378*dbed73cbSSangeeta Misra 
1379*dbed73cbSSangeeta Misra cleanup:
1380*dbed73cbSSangeeta Misra 	(void) close(fds[0]);
1381*dbed73cbSSangeeta Misra 	(void) close(fds[1]);
1382*dbed73cbSSangeeta Misra 	destroy_argv(child_argv);
1383*dbed73cbSSangeeta Misra 	if (probe_ev != NULL)
1384*dbed73cbSSangeeta Misra 		free(probe_ev);
1385*dbed73cbSSangeeta Misra 	return (B_FALSE);
1386*dbed73cbSSangeeta Misra }
1387*dbed73cbSSangeeta Misra 
1388*dbed73cbSSangeeta Misra /*
1389*dbed73cbSSangeeta Misra  * Called by ild_hc_probe_return() to re-associate the fd to a child to
1390*dbed73cbSSangeeta Misra  * the event port.
1391*dbed73cbSSangeeta Misra  */
1392*dbed73cbSSangeeta Misra static void
1393*dbed73cbSSangeeta Misra reassociate_port(int ev_port, int fd, ilbd_hc_probe_event_t *ev)
1394*dbed73cbSSangeeta Misra {
1395*dbed73cbSSangeeta Misra 	if (port_associate(ev_port, PORT_SOURCE_FD, fd,
1396*dbed73cbSSangeeta Misra 	    POLLRDNORM, ev) != 0) {
1397*dbed73cbSSangeeta Misra 		/*
1398*dbed73cbSSangeeta Misra 		 * If we cannot reassociate with the port, the only
1399*dbed73cbSSangeeta Misra 		 * thing we can do now is to kill the child and
1400*dbed73cbSSangeeta Misra 		 * do a blocking wait here...
1401*dbed73cbSSangeeta Misra 		 */
1402*dbed73cbSSangeeta Misra 		logdebug("%s: port_associate: %s", __func__, strerror(errno));
1403*dbed73cbSSangeeta Misra 		if (kill(ev->ihp_pid, SIGKILL) != 0)
1404*dbed73cbSSangeeta Misra 			logerr("%s: kill: %s", __func__, strerror(errno));
1405*dbed73cbSSangeeta Misra 		if (waitpid(ev->ihp_pid, NULL, 0) != ev->ihp_pid)
1406*dbed73cbSSangeeta Misra 			logdebug("%s: waitpid: %s", __func__, strerror(errno));
1407*dbed73cbSSangeeta Misra 		free(ev);
1408*dbed73cbSSangeeta Misra 	}
1409*dbed73cbSSangeeta Misra }
1410*dbed73cbSSangeeta Misra 
1411*dbed73cbSSangeeta Misra /*
1412*dbed73cbSSangeeta Misra  * To handle a child probe process hanging up.
1413*dbed73cbSSangeeta Misra  */
1414*dbed73cbSSangeeta Misra static void
1415*dbed73cbSSangeeta Misra ilbd_hc_child_hup(int ev_port, int fd, ilbd_hc_probe_event_t *ev)
1416*dbed73cbSSangeeta Misra {
1417*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *srv;
1418*dbed73cbSSangeeta Misra 	pid_t ret_pid;
1419*dbed73cbSSangeeta Misra 	int ret;
1420*dbed73cbSSangeeta Misra 
1421*dbed73cbSSangeeta Misra 	srv = ev->ihp_srv;
1422*dbed73cbSSangeeta Misra 
1423*dbed73cbSSangeeta Misra 	if (!ev->ihp_done) {
1424*dbed73cbSSangeeta Misra 		/* ilbd does not care about this process anymore ... */
1425*dbed73cbSSangeeta Misra 		ev->ihp_done = B_TRUE;
1426*dbed73cbSSangeeta Misra 		srv->shc_ev = NULL;
1427*dbed73cbSSangeeta Misra 		srv->shc_child_pid = 0;
1428*dbed73cbSSangeeta Misra 		HC_CANCEL_TIMER(srv);
1429*dbed73cbSSangeeta Misra 		ilbd_set_fail_state(srv);
1430*dbed73cbSSangeeta Misra 	}
1431*dbed73cbSSangeeta Misra 	ret_pid = waitpid(ev->ihp_pid, &ret, WNOHANG);
1432*dbed73cbSSangeeta Misra 	switch (ret_pid) {
1433*dbed73cbSSangeeta Misra 	case -1:
1434*dbed73cbSSangeeta Misra 		logperror("ilbd_hc_child_hup: waitpid");
1435*dbed73cbSSangeeta Misra 		/* FALLTHROUGH */
1436*dbed73cbSSangeeta Misra 	case 0:
1437*dbed73cbSSangeeta Misra 		/* The child has not completed the exit. Wait again. */
1438*dbed73cbSSangeeta Misra 		reassociate_port(ev_port, fd, ev);
1439*dbed73cbSSangeeta Misra 		break;
1440*dbed73cbSSangeeta Misra 	default:
1441*dbed73cbSSangeeta Misra 		/* Right now, we just ignore the exit status. */
1442*dbed73cbSSangeeta Misra 		if (WIFEXITED(ret))
1443*dbed73cbSSangeeta Misra 			ret = WEXITSTATUS(ret);
1444*dbed73cbSSangeeta Misra 		(void) close(fd);
1445*dbed73cbSSangeeta Misra 		free(ev);
1446*dbed73cbSSangeeta Misra 	}
1447*dbed73cbSSangeeta Misra }
1448*dbed73cbSSangeeta Misra 
1449*dbed73cbSSangeeta Misra /*
1450*dbed73cbSSangeeta Misra  * To read the output of a child probe process.
1451*dbed73cbSSangeeta Misra  */
1452*dbed73cbSSangeeta Misra static void
1453*dbed73cbSSangeeta Misra ilbd_hc_child_data(int fd, ilbd_hc_probe_event_t *ev)
1454*dbed73cbSSangeeta Misra {
1455*dbed73cbSSangeeta Misra 	ilbd_hc_srv_t *srv;
1456*dbed73cbSSangeeta Misra 	char buf[HC_MAX_PROBE_OUTPUT];
1457*dbed73cbSSangeeta Misra 	int ret;
1458*dbed73cbSSangeeta Misra 	int64_t rtt;
1459*dbed73cbSSangeeta Misra 
1460*dbed73cbSSangeeta Misra 	srv = ev->ihp_srv;
1461*dbed73cbSSangeeta Misra 
1462*dbed73cbSSangeeta Misra 	bzero(buf, HC_MAX_PROBE_OUTPUT);
1463*dbed73cbSSangeeta Misra 	ret = read(fd, buf, HC_MAX_PROBE_OUTPUT - 1);
1464*dbed73cbSSangeeta Misra 	/* Should not happen since event port should have caught this. */
1465*dbed73cbSSangeeta Misra 	assert(ret > 0);
1466*dbed73cbSSangeeta Misra 
1467*dbed73cbSSangeeta Misra 	/*
1468*dbed73cbSSangeeta Misra 	 * We expect the probe command to print out the RTT only.  But
1469*dbed73cbSSangeeta Misra 	 * the command may misbehave and print out more than what we intend to
1470*dbed73cbSSangeeta Misra 	 * read in.  So need to do this check below to "flush" out all the
1471*dbed73cbSSangeeta Misra 	 * output from the command.
1472*dbed73cbSSangeeta Misra 	 */
1473*dbed73cbSSangeeta Misra 	if (!ev->ihp_done) {
1474*dbed73cbSSangeeta Misra 		ev->ihp_done = B_TRUE;
1475*dbed73cbSSangeeta Misra 		/* We don't need to know about this event anymore. */
1476*dbed73cbSSangeeta Misra 		srv->shc_ev = NULL;
1477*dbed73cbSSangeeta Misra 		srv->shc_child_pid = 0;
1478*dbed73cbSSangeeta Misra 		HC_CANCEL_TIMER(srv);
1479*dbed73cbSSangeeta Misra 	} else {
1480*dbed73cbSSangeeta Misra 		return;
1481*dbed73cbSSangeeta Misra 	}
1482*dbed73cbSSangeeta Misra 
1483*dbed73cbSSangeeta Misra 	rtt = strtoll(buf, NULL, 10);
1484*dbed73cbSSangeeta Misra 
1485*dbed73cbSSangeeta Misra 	/*
1486*dbed73cbSSangeeta Misra 	 * -1 means the server is dead or the probe somehow fails.  Treat
1487*dbed73cbSSangeeta Misra 	 * them both as server is dead.
1488*dbed73cbSSangeeta Misra 	 */
1489*dbed73cbSSangeeta Misra 	if (rtt == -1) {
1490*dbed73cbSSangeeta Misra 		ilbd_set_fail_state(srv);
1491*dbed73cbSSangeeta Misra 		return;
1492*dbed73cbSSangeeta Misra 	} else if (rtt > 0) {
1493*dbed73cbSSangeeta Misra 		/* If the returned RTT value is not valid, just ignore it. */
1494*dbed73cbSSangeeta Misra 		if (rtt > 0 && rtt <= UINT_MAX) {
1495*dbed73cbSSangeeta Misra 			/* Set rtt to be the simple smoothed average. */
1496*dbed73cbSSangeeta Misra 			if (srv->shc_rtt == 0) {
1497*dbed73cbSSangeeta Misra 				srv->shc_rtt = rtt;
1498*dbed73cbSSangeeta Misra 			} else {
1499*dbed73cbSSangeeta Misra 				srv->shc_rtt = 3 * ((srv)->shc_rtt >> 2) +
1500*dbed73cbSSangeeta Misra 				    (rtt >> 2);
1501*dbed73cbSSangeeta Misra 			}
1502*dbed73cbSSangeeta Misra 		}
1503*dbed73cbSSangeeta Misra 
1504*dbed73cbSSangeeta Misra 	}
1505*dbed73cbSSangeeta Misra 
1506*dbed73cbSSangeeta Misra 	switch (srv->shc_state) {
1507*dbed73cbSSangeeta Misra 	case ilbd_hc_def_pinging:
1508*dbed73cbSSangeeta Misra 		srv->shc_state = ilbd_hc_probing;
1509*dbed73cbSSangeeta Misra 
1510*dbed73cbSSangeeta Misra 		/* Ping is OK, now start the probe. */
1511*dbed73cbSSangeeta Misra 		ilbd_hc_probe_timer(ilbd_hc_timer_q, srv);
1512*dbed73cbSSangeeta Misra 		break;
1513*dbed73cbSSangeeta Misra 	case ilbd_hc_probing:
1514*dbed73cbSSangeeta Misra 		srv->shc_fail_cnt = 0;
1515*dbed73cbSSangeeta Misra 
1516*dbed73cbSSangeeta Misra 		/* Server is dead before, re-enable it. */
1517*dbed73cbSSangeeta Misra 		if (srv->shc_status == ILB_HCS_UNREACH ||
1518*dbed73cbSSangeeta Misra 		    srv->shc_status == ILB_HCS_DEAD) {
1519*dbed73cbSSangeeta Misra 			/*
1520*dbed73cbSSangeeta Misra 			 * If enabling the server in kernel fails now,
1521*dbed73cbSSangeeta Misra 			 * hopefully when the timer fires again later, the
1522*dbed73cbSSangeeta Misra 			 * enabling can be done.
1523*dbed73cbSSangeeta Misra 			 */
1524*dbed73cbSSangeeta Misra 			if (ilbd_k_Xable_server(&srv->shc_sg_srv->sgs_addr,
1525*dbed73cbSSangeeta Misra 			    srv->shc_hc_rule->hcr_rule->irl_name,
1526*dbed73cbSSangeeta Misra 			    stat_declare_srv_alive) != ILB_STATUS_OK) {
1527*dbed73cbSSangeeta Misra 				logerr("%s: cannot enable server in kernel: "
1528*dbed73cbSSangeeta Misra 				    " rule %s server %s", __func__,
1529*dbed73cbSSangeeta Misra 				    srv->shc_hc_rule->hcr_rule->irl_name,
1530*dbed73cbSSangeeta Misra 				    srv->shc_sg_srv->sgs_srvID);
1531*dbed73cbSSangeeta Misra 			} else {
1532*dbed73cbSSangeeta Misra 				srv->shc_status = ILB_HCS_ALIVE;
1533*dbed73cbSSangeeta Misra 			}
1534*dbed73cbSSangeeta Misra 		} else {
1535*dbed73cbSSangeeta Misra 			srv->shc_status = ILB_HCS_ALIVE;
1536*dbed73cbSSangeeta Misra 		}
1537*dbed73cbSSangeeta Misra 		if (ilbd_hc_restart_timer(srv->shc_hc, srv) != ILB_STATUS_OK) {
1538*dbed73cbSSangeeta Misra 			logerr("%s: cannot restart timer: rule %s server %s",
1539*dbed73cbSSangeeta Misra 			    __func__, srv->shc_hc_rule->hcr_rule->irl_name,
1540*dbed73cbSSangeeta Misra 			    srv->shc_sg_srv->sgs_srvID);
1541*dbed73cbSSangeeta Misra 			ilbd_mark_server_disabled(srv);
1542*dbed73cbSSangeeta Misra 		}
1543*dbed73cbSSangeeta Misra 		break;
1544*dbed73cbSSangeeta Misra 	default:
1545*dbed73cbSSangeeta Misra 		logdebug("%s: unknown state", __func__);
1546*dbed73cbSSangeeta Misra 		break;
1547*dbed73cbSSangeeta Misra 	}
1548*dbed73cbSSangeeta Misra }
1549*dbed73cbSSangeeta Misra 
1550*dbed73cbSSangeeta Misra /*
1551*dbed73cbSSangeeta Misra  * Handle the return event of a child probe fd.
1552*dbed73cbSSangeeta Misra  */
1553*dbed73cbSSangeeta Misra void
1554*dbed73cbSSangeeta Misra ilbd_hc_probe_return(int ev_port, int fd, int port_events,
1555*dbed73cbSSangeeta Misra     ilbd_hc_probe_event_t *ev)
1556*dbed73cbSSangeeta Misra {
1557*dbed73cbSSangeeta Misra 	/*
1558*dbed73cbSSangeeta Misra 	 * Note that there can be more than one events delivered to us at
1559*dbed73cbSSangeeta Misra 	 * the same time.  So we need to check them individually.
1560*dbed73cbSSangeeta Misra 	 */
1561*dbed73cbSSangeeta Misra 	if (port_events & POLLRDNORM)
1562*dbed73cbSSangeeta Misra 		ilbd_hc_child_data(fd, ev);
1563*dbed73cbSSangeeta Misra 
1564*dbed73cbSSangeeta Misra 	if (port_events & (POLLHUP|POLLERR)) {
1565*dbed73cbSSangeeta Misra 		ilbd_hc_child_hup(ev_port, fd, ev);
1566*dbed73cbSSangeeta Misra 		return;
1567*dbed73cbSSangeeta Misra 	}
1568*dbed73cbSSangeeta Misra 
1569*dbed73cbSSangeeta Misra 	/*
1570*dbed73cbSSangeeta Misra 	 * Re-associate the fd with the port so that when the child
1571*dbed73cbSSangeeta Misra 	 * exits, we can reap the status.
1572*dbed73cbSSangeeta Misra 	 */
1573*dbed73cbSSangeeta Misra 	reassociate_port(ev_port, fd, ev);
1574*dbed73cbSSangeeta Misra }
1575