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
print_hc(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)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
ilbadm_print_hc(ilb_handle_t h,ilb_hc_info_t * hc_info,void * arg)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
ilbadm_show_hc(int argc,char * argv[])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
print_hc_result(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)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
ilbadm_print_hc_result(ilb_handle_t h,ilb_hc_srv_t * srv,void * arg)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
ilbadm_show_hc_result(int argc,char * argv[])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
ilbadm_hc_parse_arg(char * arg,ilb_hc_info_t * hc)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
ilbadm_create_hc(int argc,char * argv[])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 char 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
ilbadm_destroy_hc(int argc,char * argv[])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
ilbadm_export_hcinfo(ilb_handle_t h,ilb_hc_info_t * hc_info,void * arg)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
ilbadm_export_hc(ilb_handle_t h,FILE * fp)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