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