1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <sys/list.h> 30 #include <netinet/in.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <stdlib.h> 34 #include <strings.h> 35 #include <errno.h> 36 #include <ofmt.h> 37 #include <libilb.h> 38 #include "ilbadm.h" 39 40 extern int optind, optopt, opterr; 41 extern char *optarg; 42 43 typedef struct hc_export_arg { 44 FILE *fp; 45 } hc_export_arg_t; 46 47 /* Maximum columns for printing hc output. */ 48 #define SHOW_HC_COLS 80 49 50 /* OFMT call back to print out a hc server result field. */ 51 static boolean_t print_hc_result(ofmt_arg_t *, char *, uint_t); 52 53 /* ID to indicate which field to be printed. */ 54 enum hc_print_id { 55 hc_of_rname, hc_of_hname, hc_of_sname, hc_of_status, hc_of_fail_cnt, 56 hc_of_lasttime, hc_of_nexttime, hc_of_rtt, 57 hc_of_name, hc_of_timeout, hc_of_count, hc_of_interval, hc_of_def_ping, 58 hc_of_test 59 }; 60 61 /* 62 * Fields of a hc server result. The sum of all fields' width is SHOW_HC_COLS. 63 */ 64 static ofmt_field_t hc_results[] = { 65 {"RULENAME", 14, hc_of_rname, print_hc_result}, 66 {"HCNAME", 14, hc_of_hname, print_hc_result}, 67 {"SERVERID", 14, hc_of_sname, print_hc_result}, 68 {"STATUS", 9, hc_of_status, print_hc_result}, 69 {"FAIL", 5, hc_of_fail_cnt, print_hc_result}, 70 {"LAST", 9, hc_of_lasttime, print_hc_result}, 71 {"NEXT", 9, hc_of_nexttime, print_hc_result}, 72 {"RTT", 6, hc_of_rtt, print_hc_result}, 73 {NULL, 0, 0, NULL} 74 }; 75 76 /* OFMT call back to print out a hc info field. */ 77 static boolean_t print_hc(ofmt_arg_t *, char *, uint_t); 78 79 /* 80 * Fields of a hc info. The sume of all fields' width is SHOW_HC_COLS. 81 */ 82 static ofmt_field_t hc_fields[] = { 83 {"HCNAME", 14, hc_of_name, print_hc}, 84 {"TIMEOUT", 8, hc_of_timeout, print_hc}, 85 {"COUNT", 8, hc_of_count, print_hc}, 86 {"INTERVAL", 9, hc_of_interval, print_hc}, 87 {"DEF_PING", 9, hc_of_def_ping, print_hc}, 88 {"TEST", 32, hc_of_test, print_hc}, 89 {NULL, 0, 0, NULL} 90 }; 91 92 static boolean_t 93 print_hc(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 94 { 95 enum hc_print_id id = of_arg->ofmt_id; 96 ilb_hc_info_t *info = (ilb_hc_info_t *)of_arg->ofmt_cbarg; 97 98 switch (id) { 99 case hc_of_name: 100 (void) strlcpy(buf, info->hci_name, bufsize); 101 break; 102 case hc_of_timeout: 103 (void) snprintf(buf, bufsize, "%d", info->hci_timeout); 104 break; 105 case hc_of_count: 106 (void) snprintf(buf, bufsize, "%d", info->hci_count); 107 break; 108 case hc_of_interval: 109 (void) snprintf(buf, bufsize, "%d", info->hci_interval); 110 break; 111 case hc_of_def_ping: 112 (void) snprintf(buf, bufsize, "%c", 113 info->hci_def_ping ? 'Y' : 'N'); 114 break; 115 case hc_of_test: 116 (void) snprintf(buf, bufsize, "%s", info->hci_test); 117 break; 118 } 119 return (B_TRUE); 120 } 121 122 /* Call back to ilb_walk_hc(). */ 123 /* ARGSUSED */ 124 static ilb_status_t 125 ilbadm_print_hc(ilb_handle_t h, ilb_hc_info_t *hc_info, void *arg) 126 { 127 ofmt_handle_t ofmt_h = arg; 128 129 ofmt_print(ofmt_h, hc_info); 130 return (ILB_STATUS_OK); 131 } 132 133 /* 134 * Print out health check objects given their name. 135 * Or print out all health check objects if no name given. 136 */ 137 /* ARGSUSED */ 138 ilbadm_status_t 139 ilbadm_show_hc(int argc, char *argv[]) 140 { 141 ilb_handle_t h = ILB_INVALID_HANDLE; 142 ilb_status_t rclib; 143 ofmt_handle_t ofmt_h; 144 ofmt_status_t ofmt_ret; 145 146 if ((ofmt_ret = ofmt_open("all", hc_fields, 0, SHOW_HC_COLS, 147 &ofmt_h)) != OFMT_SUCCESS) { 148 char err_buf[SHOW_HC_COLS]; 149 150 ilbadm_err(gettext("ofmt_open failed: %s"), 151 ofmt_strerror(ofmt_h, ofmt_ret, err_buf, SHOW_HC_COLS)); 152 return (ILBADM_LIBERR); 153 } 154 rclib = ilb_open(&h); 155 if (rclib != ILB_STATUS_OK) 156 goto out; 157 158 if (argc == 1) { 159 rclib = ilb_walk_hc(h, ilbadm_print_hc, ofmt_h); 160 } else { 161 ilb_hc_info_t hc_info; 162 int i; 163 164 for (i = 1; i < argc; i++) { 165 rclib = ilb_get_hc_info(h, argv[i], &hc_info); 166 if (rclib == ILB_STATUS_OK) 167 ofmt_print(ofmt_h, &hc_info); 168 else 169 break; 170 } 171 } 172 out: 173 ofmt_close(ofmt_h); 174 175 if (h != ILB_INVALID_HANDLE) 176 (void) ilb_close(h); 177 178 if (rclib != ILB_STATUS_OK) { 179 ilbadm_err(ilb_errstr(rclib)); 180 return (ILBADM_LIBERR); 181 } 182 183 return (ILBADM_OK); 184 } 185 186 static boolean_t 187 print_hc_result(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 188 { 189 enum hc_print_id id = of_arg->ofmt_id; 190 ilb_hc_srv_t *srv = (ilb_hc_srv_t *)of_arg->ofmt_cbarg; 191 struct tm tv; 192 193 switch (id) { 194 case hc_of_rname: 195 (void) strlcpy(buf, srv->hcs_rule_name, bufsize); 196 break; 197 case hc_of_hname: 198 (void) strlcpy(buf, srv->hcs_hc_name, bufsize); 199 break; 200 case hc_of_sname: 201 (void) strlcpy(buf, srv->hcs_ID, bufsize); 202 break; 203 case hc_of_status: 204 switch (srv->hcs_status) { 205 case ILB_HCS_UNINIT: 206 (void) strlcpy(buf, "un-init", bufsize); 207 break; 208 case ILB_HCS_UNREACH: 209 (void) strlcpy(buf, "unreach", bufsize); 210 break; 211 case ILB_HCS_ALIVE: 212 (void) strlcpy(buf, "alive", bufsize); 213 break; 214 case ILB_HCS_DEAD: 215 (void) strlcpy(buf, "dead", bufsize); 216 break; 217 case ILB_HCS_DISABLED: 218 (void) strlcpy(buf, "disabled", bufsize); 219 break; 220 } 221 break; 222 case hc_of_fail_cnt: 223 (void) snprintf(buf, bufsize, "%u", srv->hcs_fail_cnt); 224 break; 225 case hc_of_lasttime: 226 if (localtime_r(&srv->hcs_lasttime, &tv) == NULL) 227 return (B_FALSE); 228 (void) snprintf(buf, bufsize, "%02d:%02d:%02d", tv.tm_hour, 229 tv.tm_min, tv.tm_sec); 230 break; 231 case hc_of_nexttime: 232 if (srv->hcs_status == ILB_HCS_DISABLED) 233 break; 234 if (localtime_r(&srv->hcs_nexttime, &tv) == NULL) 235 return (B_FALSE); 236 (void) snprintf(buf, bufsize, "%02d:%02d:%02d", tv.tm_hour, 237 tv.tm_min, tv.tm_sec); 238 break; 239 case hc_of_rtt: 240 (void) snprintf(buf, bufsize, "%u", srv->hcs_rtt); 241 break; 242 } 243 return (B_TRUE); 244 } 245 246 /* Call back to ilbd_walk_hc_srvs(). */ 247 /* ARGSUSED */ 248 static ilb_status_t 249 ilbadm_print_hc_result(ilb_handle_t h, ilb_hc_srv_t *srv, void *arg) 250 { 251 ofmt_handle_t ofmt_h = arg; 252 253 ofmt_print(ofmt_h, srv); 254 return (ILB_STATUS_OK); 255 } 256 257 /* 258 * Output hc result of a specified rule or all rules. 259 */ 260 ilbadm_status_t 261 ilbadm_show_hc_result(int argc, char *argv[]) 262 { 263 ilb_handle_t h = ILB_INVALID_HANDLE; 264 ilb_status_t rclib = ILB_STATUS_OK; 265 int i; 266 ofmt_handle_t ofmt_h; 267 ofmt_status_t ofmt_ret; 268 269 /* ilbadm show-hc-result [rule-name] */ 270 if (argc < 1) { 271 ilbadm_err(gettext("usage: ilbadm show-hc-result" 272 " [rule-name]")); 273 return (ILBADM_LIBERR); 274 } 275 276 if ((ofmt_ret = ofmt_open("all", hc_results, 0, SHOW_HC_COLS, 277 &ofmt_h)) != OFMT_SUCCESS) { 278 char err_buf[SHOW_HC_COLS]; 279 280 ilbadm_err(gettext("ofmt_open failed: %s"), 281 ofmt_strerror(ofmt_h, ofmt_ret, err_buf, SHOW_HC_COLS)); 282 return (ILBADM_LIBERR); 283 } 284 285 rclib = ilb_open(&h); 286 if (rclib != ILB_STATUS_OK) 287 goto out; 288 289 /* If no rule name is given, show results for all rules. */ 290 if (argc == 1) { 291 rclib = ilb_walk_hc_srvs(h, ilbadm_print_hc_result, NULL, 292 ofmt_h); 293 } else { 294 for (i = 1; i < argc; i++) { 295 rclib = ilb_walk_hc_srvs(h, ilbadm_print_hc_result, 296 argv[i], ofmt_h); 297 if (rclib != ILB_STATUS_OK) 298 break; 299 } 300 } 301 out: 302 ofmt_close(ofmt_h); 303 304 if (h != ILB_INVALID_HANDLE) 305 (void) ilb_close(h); 306 307 if (rclib != ILB_STATUS_OK) { 308 ilbadm_err(ilb_errstr(rclib)); 309 return (ILBADM_LIBERR); 310 } 311 return (ILBADM_OK); 312 } 313 314 #define ILBADM_DEF_HC_COUNT 3 315 #define ILBADM_DEF_HC_INTERVAL 30 /* in sec */ 316 #define ILBADM_DEF_HC_TIMEOUT 5 /* in sec */ 317 318 static ilbadm_key_name_t hc_parse_keys[] = { 319 {ILB_KEY_HC_TEST, "hc-test", "hc-test"}, 320 {ILB_KEY_HC_COUNT, "hc-count", "hc-count"}, 321 {ILB_KEY_HC_TIMEOUT, "hc-timeout", "hc-tout"}, 322 {ILB_KEY_HC_INTERVAL, "hc-interval", "hc-intl"}, 323 {ILB_KEY_BAD, "", ""} 324 }; 325 326 static ilbadm_status_t 327 ilbadm_hc_parse_arg(char *arg, ilb_hc_info_t *hc) 328 { 329 ilbadm_status_t ret; 330 331 /* set default value for count, interval, timeout */ 332 hc->hci_count = ILBADM_DEF_HC_COUNT; 333 hc->hci_interval = ILBADM_DEF_HC_INTERVAL; 334 hc->hci_timeout = ILBADM_DEF_HC_TIMEOUT; 335 hc->hci_test[0] = '\0'; 336 337 ret = i_parse_optstring(arg, hc, hc_parse_keys, 0, NULL); 338 if (ret != ILBADM_OK && ret != ILBADM_LIBERR) { 339 ilbadm_err(ilbadm_errstr(ret)); 340 return (ILBADM_LIBERR); 341 } 342 if (hc->hci_test[0] == '\0' && ret != ILBADM_LIBERR) { 343 ilbadm_err("hc-test: missing"); 344 return (ILBADM_LIBERR); 345 } 346 return (ret); 347 } 348 349 /* ARGSUSED */ 350 ilbadm_status_t 351 ilbadm_create_hc(int argc, char *argv[]) 352 { 353 ilb_handle_t h = ILB_INVALID_HANDLE; 354 ilb_hc_info_t hc_info; 355 ilbadm_status_t ret = ILBADM_OK; 356 ilb_status_t rclib; 357 int c; 358 359 360 hc_info.hci_def_ping = B_TRUE; 361 while ((c = getopt(argc, argv, ":h:n")) != -1) { 362 if (c == 'h') { 363 ret = ilbadm_hc_parse_arg(optarg, &hc_info); 364 if (ret != ILBADM_OK) 365 return (ret); 366 } else if (c == 'n') { 367 hc_info.hci_def_ping = B_FALSE; 368 } else { 369 ilbadm_err(gettext("bad argument %c"), c); 370 return (ILBADM_LIBERR); 371 } 372 } 373 374 if (optind >= argc) { 375 ilbadm_err(gettext("usage: ilbadm" 376 " create-healthcheck [-n] -h" 377 " hc-test=val[,hc-timeout=val][,hc-count=va]" 378 "[,hc-interval=val] hc-name")); 379 return (ILBADM_FAIL); 380 } 381 382 if (strlen(argv[optind]) > ILBD_NAMESZ - 1) { 383 ilbadm_err(gettext("health check object name %s is too long - " 384 "must not exceed %d chars"), argv[optind], 385 ILBD_NAMESZ - 1); 386 return (ILBADM_FAIL); 387 } 388 389 if (((strcasecmp(hc_info.hci_test, ILB_HC_STR_UDP) == 0) || 390 (strcasecmp(hc_info.hci_test, ILB_HC_STR_PING) == 0)) && 391 !(hc_info.hci_def_ping)) { 392 ilbadm_err(gettext("cannot disable default PING" 393 " for this test")); 394 return (ILBADM_LIBERR); 395 } 396 397 rclib = ilb_open(&h); 398 if (rclib != ILB_STATUS_OK) 399 goto out; 400 401 (void) strlcpy(hc_info.hci_name, argv[optind], 402 sizeof (hc_info.hci_name)); 403 rclib = ilb_create_hc(h, &hc_info); 404 out: 405 if (h != ILB_INVALID_HANDLE) 406 (void) ilb_close(h); 407 408 if (rclib != ILB_STATUS_OK) { 409 ilbadm_err(ilb_errstr(rclib)); 410 ret = ILBADM_LIBERR; 411 } 412 return (ret); 413 } 414 415 ilbadm_status_t 416 ilbadm_destroy_hc(int argc, char *argv[]) 417 { 418 ilb_handle_t h = ILB_INVALID_HANDLE; 419 ilb_status_t rclib; 420 ilbadm_status_t ret = ILBADM_OK; 421 int i; 422 423 if (argc < 2) { 424 ilbadm_err(gettext("usage: ilbadm" 425 " delete-healthcheck hc-name ...")); 426 return (ILBADM_LIBERR); 427 } 428 429 rclib = ilb_open(&h); 430 if (rclib != ILB_STATUS_OK) 431 goto out; 432 433 for (i = 1; i < argc; i++) { 434 rclib = ilb_destroy_hc(h, argv[i]); 435 if (rclib != ILB_STATUS_OK) 436 break; 437 } 438 out: 439 if (h != ILB_INVALID_HANDLE) 440 (void) ilb_close(h); 441 442 if (rclib != ILB_STATUS_OK) { 443 ilbadm_err(ilb_errstr(rclib)); 444 ret = ILBADM_LIBERR; 445 } 446 return (ret); 447 } 448 449 /* 450 * Since this function is used by libilb function, it 451 * must return libilb errors 452 */ 453 /* ARGSUSED */ 454 ilb_status_t 455 ilbadm_export_hcinfo(ilb_handle_t h, ilb_hc_info_t *hc_info, void *arg) 456 { 457 FILE *fp = ((hc_export_arg_t *)arg)->fp; 458 int count = 0; 459 int ret; 460 461 /* 462 * a test name "PING" implies "no default ping", so we only 463 * print -n if the test is NOT "PING" 464 */ 465 if (hc_info->hci_def_ping == B_FALSE && 466 strncasecmp(hc_info->hci_test, "PING", 5) != 0) 467 (void) fprintf(fp, "create-healthcheck -n -h "); 468 else 469 (void) fprintf(fp, "create-healthcheck -h "); 470 471 if (*hc_info->hci_test != '\0') { 472 (void) fprintf(fp, "hc-test=%s", hc_info->hci_test); 473 count++; 474 } 475 if (hc_info->hci_timeout != 0) { 476 if (count++ > 0) 477 (void) fprintf(fp, ","); 478 (void) fprintf(fp, "hc-timeout=%d", hc_info->hci_timeout); 479 } 480 if (hc_info->hci_count != 0) { 481 if (count++ > 0) 482 (void) fprintf(fp, ","); 483 (void) fprintf(fp, "hc-count=%d", hc_info->hci_count); 484 } 485 if (hc_info->hci_interval != 0) { 486 if (count > 0) 487 (void) fprintf(fp, ","); 488 (void) fprintf(fp, "hc-interval=%d", hc_info->hci_interval); 489 } 490 491 /* 492 * if any of the above writes fails, then, we assume, so will 493 * this one; so it's sufficient to test once 494 */ 495 ret = fprintf(fp, " %s\n", hc_info->hci_name); 496 if (ret < 0) 497 goto out_fail; 498 ret = fflush(fp); 499 500 out_fail: 501 if (ret < 0) 502 return (ILB_STATUS_WRITE); 503 return (ILB_STATUS_OK); 504 } 505 506 ilbadm_status_t 507 ilbadm_export_hc(ilb_handle_t h, FILE *fp) 508 { 509 ilb_status_t rclib; 510 ilbadm_status_t ret = ILBADM_OK; 511 hc_export_arg_t arg; 512 513 arg.fp = fp; 514 rclib = ilb_walk_hc(h, ilbadm_export_hcinfo, (void *)&arg); 515 if (rclib != ILB_STATUS_OK) { 516 ilbadm_err(ilb_errstr(rclib)); 517 ret = ILBADM_LIBERR; 518 } 519 return (ret); 520 } 521