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