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 <stdio.h> 28 #include <unistd.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <errno.h> 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <netinet/in.h> 35 #include <arpa/inet.h> 36 #include <sys/list.h> 37 #include <netdb.h> 38 #include <ofmt.h> 39 #include <assert.h> 40 #include <libilb.h> 41 #include "ilbadm.h" 42 43 static ilbadm_key_name_t rl_incoming_keys[] = { 44 {ILB_KEY_VIP, "vip", ""}, 45 {ILB_KEY_PORT, "port", ""}, 46 {ILB_KEY_PROTOCOL, "protocol", "prot"}, 47 {ILB_KEY_BAD, "", ""} 48 }; 49 static ilbadm_key_name_t rl_method_keys[] = { 50 {ILB_KEY_ALGORITHM, "lbalg", "algo"}, 51 {ILB_KEY_TYPE, "type", "topo"}, 52 {ILB_KEY_SRC, "proxy-src", "nat-src"}, 53 {ILB_KEY_STICKY, "pmask", "persist"}, 54 {ILB_KEY_BAD, "", ""} 55 }; 56 static ilbadm_key_name_t rl_outgoing_keys[] = { 57 {ILB_KEY_SERVERGROUP, "servergroup", "sg"}, 58 {ILB_KEY_BAD, "", ""} 59 }; 60 static ilbadm_key_name_t rl_healthchk_keys[] = { 61 {ILB_KEY_HEALTHCHECK, "hc-name", "hcn"}, 62 {ILB_KEY_HCPORT, "hc-port", "hcp"}, 63 {ILB_KEY_BAD, "", ""} 64 }; 65 static ilbadm_key_name_t rl_timer_keys[] = { 66 {ILB_KEY_CONNDRAIN, "conn-drain", ""}, 67 {ILB_KEY_NAT_TO, "nat-timeout", ""}, 68 {ILB_KEY_STICKY_TO, "persist-timeout", ""}, 69 {ILB_KEY_BAD, "", ""} 70 }; 71 72 static ilbadm_key_name_t *all_keys[] = { 73 rl_incoming_keys, rl_method_keys, rl_outgoing_keys, 74 rl_healthchk_keys, rl_timer_keys, NULL 75 }; 76 77 78 /* field ids for of_* functions */ 79 #define OF_IP_VIP 0 80 #define OF_IP_PROXYSRC 1 81 #define OF_IP_STICKYMASK 2 82 83 #define OF_STR_RNAME 0 84 #define OF_STR_HCNAME 1 85 #define OF_STR_SGNAME 2 86 #define OF_STR_INTERFACE 3 87 88 #define OF_PORT 0 89 #define OF_HCPORT 1 90 91 #define OF_T_CONN 0 92 #define OF_T_NAT 1 93 #define OF_T_STICKY 2 94 95 #define OF_SRV_ID 0 96 #define OF_SRV_ADDR 1 97 #define OF_SRV_PORT 2 98 #define OF_SRV_STATUS 3 99 #define OF_SRV_RNAME 4 100 #define OF_SRV_SGNAME 5 101 #define OF_SRV_HOSTNAME 6 102 103 /* some field sizes of ofmt_field_t arrays */ 104 #define IPv4_FIELDWIDTH 16 105 #define IPv6_FIELDWIDTH 39 106 #define ILB_HOSTNAMELEN 20 107 #define ILB_STATUSFIELD_LEN 7 108 109 typedef struct arg_struct { 110 int flags; 111 char *o_str; 112 ofmt_field_t *o_fields; 113 ofmt_handle_t oh; 114 } ilbadm_sh_rl_arg_t; 115 116 typedef struct ilbadm_rl_exp_arg { 117 FILE *fp; 118 } ilbadm_rl_exp_arg_t; 119 120 typedef struct ilbadm_rl_list_arg { 121 ilb_handle_t h; 122 ilb_rule_data_t *rd; 123 } ilbadm_rl_list_arg_t; 124 125 typedef struct ilbadm_rl_srvlist_arg { 126 char *sgname; 127 ilb_server_data_t *sd; 128 ilb_rule_data_t *rd; 129 int flags; 130 char *o_str; 131 ofmt_field_t *o_fields; 132 ofmt_handle_t oh; 133 } ilbadm_rl_srvlist_arg_t; 134 135 static ofmt_cb_t of_algo; 136 static ofmt_cb_t of_proto; 137 static ofmt_cb_t of_rl_ip; 138 static ofmt_cb_t of_rl_mask; 139 static ofmt_cb_t of_rport; 140 static ofmt_cb_t of_rstatus; 141 static ofmt_cb_t of_str; 142 static ofmt_cb_t of_time; 143 static ofmt_cb_t of_topo; 144 static ofmt_cb_t of_rl_srvlist; 145 146 static boolean_t of_srv2str(ofmt_arg_t *, char *, uint_t); 147 static boolean_t of_port2str(in_port_t, in_port_t, char *, uint_t); 148 149 static ofmt_field_t rfields_v4[] = { 150 {"RULENAME", ILB_NAMESZ, OF_STR_RNAME, of_str}, 151 {"STATUS", ILB_STATUSFIELD_LEN, 0, of_rstatus}, 152 {"PORT", 10, OF_PORT, of_rport}, 153 {"PROTOCOL", 5, 0, of_proto}, 154 {"LBALG", 12, 0, of_algo}, 155 {"TYPE", 8, 0, of_topo}, 156 {"PROXY-SRC", 2*IPv4_FIELDWIDTH+1, OF_IP_PROXYSRC, of_rl_ip}, 157 {"PMASK", 6, OF_IP_STICKYMASK, of_rl_mask}, 158 {"HC-NAME", ILB_NAMESZ, OF_STR_HCNAME, of_str}, 159 {"HC-PORT", 8, OF_HCPORT, of_rport}, 160 {"CONN-DRAIN", 11, OF_T_CONN, of_time}, 161 {"NAT-TIMEOUT", 12, OF_T_NAT, of_time}, 162 {"PERSIST-TIMEOUT", 16, OF_T_STICKY, of_time}, 163 {"SERVERGROUP", ILB_SGNAME_SZ, OF_STR_SGNAME, of_str}, 164 {"VIP", IPv4_FIELDWIDTH, OF_IP_VIP, of_rl_ip}, 165 {"SERVERS", 20, 0, of_rl_srvlist}, 166 {NULL, 0, 0, NULL} 167 }; 168 169 static ofmt_field_t rfields_v6[] = { 170 {"RULENAME", ILB_NAMESZ, OF_STR_RNAME, of_str}, 171 {"STATUS", ILB_STATUSFIELD_LEN, 0, of_rstatus}, 172 {"PORT", 10, OF_PORT, of_rport}, 173 {"PROTOCOL", 5, 0, of_proto}, 174 {"LBALG", 12, 0, of_algo}, 175 {"TYPE", 8, 0, of_topo}, 176 {"PROXY-SRC", IPv6_FIELDWIDTH, OF_IP_PROXYSRC, of_rl_ip}, 177 {"PMASK", 6, OF_IP_STICKYMASK, of_rl_mask}, 178 {"HC-NAME", ILB_NAMESZ, OF_STR_HCNAME, of_str}, 179 {"HC-PORT", 8, OF_HCPORT, of_rport}, 180 {"CONN-DRAIN", 11, OF_T_CONN, of_time}, 181 {"NAT-TIMEOUT", 12, OF_T_NAT, of_time}, 182 {"PERSIST-TIMEOUT", 16, OF_T_STICKY, of_time}, 183 {"SERVERGROUP", ILB_SGNAME_SZ, OF_STR_SGNAME, of_str}, 184 {"VIP", IPv6_FIELDWIDTH, OF_IP_VIP, of_rl_ip}, 185 {"SERVERS", 20, 0, of_rl_srvlist}, 186 {NULL, 0, 0, NULL} 187 }; 188 189 static ofmt_field_t ssfields_v4[] = { 190 {"SERVERID", ILB_NAMESZ, OF_SRV_ID, of_srv2str}, 191 {"ADDRESS", IPv4_FIELDWIDTH, OF_SRV_ADDR, of_srv2str}, 192 {"PORT", 5, OF_SRV_PORT, of_srv2str}, 193 {"RULENAME", ILB_NAMESZ, OF_SRV_RNAME, of_srv2str}, 194 {"STATUS", ILB_STATUSFIELD_LEN, OF_SRV_STATUS, of_srv2str}, 195 {"SERVERGROUP", ILB_SGNAME_SZ, OF_SRV_SGNAME, of_srv2str}, 196 {"HOSTNAME", ILB_HOSTNAMELEN, OF_SRV_HOSTNAME, of_srv2str}, 197 {NULL, 0, 0, NULL} 198 }; 199 200 static ofmt_field_t ssfields_v6[] = { 201 {"SERVERID", ILB_NAMESZ, OF_SRV_ID, of_srv2str}, 202 {"ADDRESS", IPv6_FIELDWIDTH, OF_SRV_ADDR, of_srv2str}, 203 {"PORT", 5, OF_SRV_PORT, of_srv2str}, 204 {"RULENAME", ILB_NAMESZ, OF_SRV_RNAME, of_srv2str}, 205 {"STATUS", ILB_STATUSFIELD_LEN, OF_SRV_STATUS, of_srv2str}, 206 {"SERVERGROUP", ILB_SGNAME_SZ, OF_SRV_SGNAME, of_srv2str}, 207 {"HOSTNAME", ILB_HOSTNAMELEN, OF_SRV_HOSTNAME, of_srv2str}, 208 {NULL, 0, 0, NULL} 209 }; 210 211 extern int optind, optopt, opterr; 212 extern char *optarg; 213 214 extern ilbadm_val_type_t algo_types[]; 215 extern ilbadm_val_type_t topo_types[]; 216 217 static char * 218 i_key_to_opt(ilbadm_key_name_t *n, ilbadm_key_code_t k) 219 { 220 int i; 221 222 for (i = 0; n[i].k_key != ILB_KEY_BAD; i++) 223 if (n[i].k_key == k) 224 break; 225 226 return (n[i].k_name); 227 } 228 229 char * 230 ilbadm_key_to_opt(ilbadm_key_code_t k) 231 { 232 char *name; 233 int i; 234 235 for (i = 0; all_keys[i] != NULL; i++) { 236 name = i_key_to_opt(all_keys[i], k); 237 if (*name != '\0') 238 return (name); 239 } 240 241 return (NULL); 242 } 243 244 /* 245 * ports are in HOST byte order 246 */ 247 static void 248 ports2str(short port1, short port2, char *buf, const int sz) 249 { 250 if (port2 <= port1) 251 (void) snprintf(buf, sz, "port=%d", port1); 252 else 253 (void) snprintf(buf, sz, "port=%d-%d", port1, port2); 254 } 255 256 static void 257 proto2str(short proto, char *buf, int sz) 258 { 259 struct protoent *pe; 260 261 pe = getprotobynumber((int)proto); 262 if (pe != NULL) 263 (void) snprintf(buf, sz, "protocol=%s", pe->p_name); 264 else 265 (void) sprintf(buf, "(bad proto %d)", proto); 266 } 267 268 static void 269 algo2str(ilb_algo_t algo, char *buf, int sz) 270 { 271 char *s = i_str_from_val((int)algo, &algo_types[0]); 272 273 (void) snprintf(buf, sz, "lbalg=%s", (s && *s) ? s : "(bad algo)"); 274 } 275 276 static int 277 algo2bare_str(ilb_algo_t algo, char *buf, int sz) 278 { 279 char *s = i_str_from_val((int)algo, &algo_types[0]); 280 281 return (snprintf(buf, sz, "%s", (s && *s) ? s : "")); 282 } 283 284 static void 285 topo2str(ilb_topo_t topo, char *buf, int sz) 286 { 287 char *s = i_str_from_val((int)topo, &topo_types[0]); 288 289 (void) snprintf(buf, sz, "type=%s", (s && *s) ? s : "(bad type)"); 290 } 291 292 static int 293 topo2bare_str(ilb_topo_t topo, char *buf, int sz) 294 { 295 char *s = i_str_from_val((int)topo, &topo_types[0]); 296 297 return (snprintf(buf, sz, "%s", (s && *s) ? s : "")); 298 } 299 300 static boolean_t 301 of_str(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 302 { 303 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 304 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 305 306 switch (of_arg->ofmt_id) { 307 case OF_STR_RNAME: 308 (void) strlcpy(buf, rd->r_name, bufsize); 309 break; 310 case OF_STR_SGNAME: 311 (void) strlcpy(buf, rd->r_sgname, bufsize); 312 break; 313 case OF_STR_HCNAME: 314 if (rd->r_hcname != NULL && *(rd->r_hcname) != '\0') 315 (void) strlcpy(buf, rd->r_hcname, bufsize); 316 break; 317 } 318 return (B_TRUE); 319 } 320 321 /* ARGSUSED */ 322 static boolean_t 323 of_proto(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 324 { 325 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 326 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 327 328 if (rd->r_proto == IPPROTO_TCP) 329 (void) strlcpy(buf, "TCP", bufsize); 330 else if (rd->r_proto == IPPROTO_UDP) 331 (void) strlcpy(buf, "UDP", bufsize); 332 else 333 return (B_FALSE); 334 return (B_TRUE); 335 } 336 337 static boolean_t 338 of_rl_ip(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 339 { 340 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 341 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 342 ilb_ip_addr_t *ip = NULL, *ip2 = NULL; 343 344 switch (of_arg->ofmt_id) { 345 case OF_IP_VIP: 346 ip = &rd->r_vip; 347 break; 348 case OF_IP_PROXYSRC: 349 ip = &rd->r_nat_src_start; 350 ip2 = &rd->r_nat_src_end; 351 break; 352 case OF_IP_STICKYMASK: 353 ip = &rd->r_stickymask; 354 break; 355 } 356 357 /* only print something valid */ 358 if (ip != NULL && (ip->ia_af == AF_INET || ip->ia_af == AF_INET6)) 359 ip2str(ip, buf, bufsize, V6_ADDRONLY); 360 if (ip2 != NULL && (ip2->ia_af == AF_INET || ip2->ia_af == AF_INET6) && 361 buf[0] != '\0') { 362 int sl = strlen(buf); 363 364 buf += sl; bufsize -= sl; 365 *buf++ = '-'; bufsize--; 366 ip2str(ip2, buf, bufsize, V6_ADDRONLY); 367 } 368 369 return (B_TRUE); 370 } 371 372 static boolean_t 373 of_rl_mask(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 374 { 375 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 376 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 377 ilb_ip_addr_t *ip = NULL; 378 379 assert(of_arg->ofmt_id == OF_IP_STICKYMASK); 380 if (!(rd->r_flags & ILB_FLAGS_RULE_STICKY)) 381 return (B_TRUE); 382 ip = &rd->r_stickymask; 383 384 (void) snprintf(buf, bufsize, "/%d", ilbadm_mask_to_prefixlen(ip)); 385 return (B_TRUE); 386 } 387 388 static void 389 hcport_print(ilb_rule_data_t *rd, char *buf, uint_t bufsize) 390 { 391 if (rd->r_hcport != 0) 392 (void) snprintf(buf, bufsize, "%d", ntohs(rd->r_hcport)); 393 else if (rd->r_hcpflag == ILB_HCI_PROBE_ANY) 394 (void) snprintf(buf, bufsize, "ANY"); 395 else 396 buf[0] = '\0'; 397 } 398 static boolean_t 399 of_rport(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 400 { 401 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 402 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 403 404 if (of_arg->ofmt_id == OF_PORT) 405 return (of_port2str(rd->r_minport, rd->r_maxport, buf, 406 bufsize)); 407 408 /* only print a hcport if there's a hc name as well */ 409 if (of_arg->ofmt_id == OF_HCPORT && rd->r_hcname[0] != '\0') 410 hcport_print(rd, buf, bufsize); 411 412 return (B_TRUE); 413 } 414 415 /* ARGSUSED */ 416 static boolean_t 417 of_rstatus(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 418 { 419 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 420 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 421 422 if ((rd->r_flags & ILB_FLAGS_RULE_ENABLED) == ILB_FLAGS_RULE_ENABLED) 423 buf[0] = 'E'; 424 else 425 buf[0] = 'D'; 426 buf[1] = '\0'; 427 return (B_TRUE); 428 } 429 430 static boolean_t 431 of_algo(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 432 { 433 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 434 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 435 436 if (algo2bare_str(rd->r_algo, buf, bufsize) == 0) 437 return (B_FALSE); 438 return (B_TRUE); 439 } 440 441 static boolean_t 442 of_topo(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 443 { 444 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 445 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 446 447 if (topo2bare_str(rd->r_topo, buf, bufsize) == 0) 448 return (B_FALSE); 449 return (B_TRUE); 450 } 451 452 static boolean_t 453 of_time(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 454 { 455 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 456 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 457 458 switch (of_arg->ofmt_id) { 459 case OF_T_CONN: 460 (void) snprintf(buf, bufsize, "%u", rd->r_conndrain); 461 break; 462 case OF_T_NAT: 463 (void) snprintf(buf, bufsize, "%u", rd->r_nat_timeout); 464 break; 465 case OF_T_STICKY: 466 (void) snprintf(buf, bufsize, "%u", rd->r_sticky_timeout); 467 break; 468 } 469 return (B_TRUE); 470 } 471 472 typedef struct rl_showlist_arg { 473 char *buf; 474 uint_t bufsize; 475 } rl_showlist_arg_t; 476 477 /* ARGSUSED */ 478 /* called by ilb_walk_servers(), cannot get rid of unused args */ 479 static ilb_status_t 480 srv2srvID(ilb_handle_t h, ilb_server_data_t *sd, const char *sgname, void *arg) 481 { 482 rl_showlist_arg_t *sla = (rl_showlist_arg_t *)arg; 483 int len; 484 485 (void) snprintf(sla->buf, sla->bufsize, "%s,", sd->sd_srvID); 486 len = strlen(sd->sd_srvID) + 1; 487 sla->buf += len; 488 sla->bufsize -= len; 489 490 return (ILB_STATUS_OK); 491 } 492 493 static boolean_t 494 of_rl_srvlist(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 495 { 496 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg; 497 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd; 498 rl_showlist_arg_t sla; 499 500 sla.buf = buf; 501 sla.bufsize = bufsize; 502 503 (void) ilb_walk_servers(ra->h, srv2srvID, rd->r_sgname, 504 (void *)&sla); 505 /* we're trailing a ',' which we need to remove */ 506 *--sla.buf = '\0'; 507 508 return (B_TRUE); 509 } 510 511 #define RMAXCOLS 120 /* enough? */ 512 #define SERVER_WIDTH (ILB_NAMESZ+1) /* 1st guess */ 513 514 static boolean_t 515 of_port2str(in_port_t minport, in_port_t maxport, char *buf, uint_t bufsize) 516 { 517 in_port_t h_min, h_max; 518 int len; 519 520 h_min = ntohs(minport); 521 h_max = ntohs(maxport); 522 523 if (h_min == 0) 524 return (B_FALSE); /* print "unspec" == "all ports" */ 525 526 len = snprintf(buf, bufsize, "%d", h_min); 527 if (h_max > h_min) 528 (void) snprintf(buf + len, bufsize - len, "-%d", h_max); 529 return (B_TRUE); 530 } 531 532 static ilbadm_status_t 533 ip2hostname(ilb_ip_addr_t *ip, char *buf, uint_t bufsize) 534 { 535 int ret; 536 struct hostent *he; 537 538 switch (ip->ia_af) { 539 case AF_INET: 540 he = getipnodebyaddr((char *)&ip->ia_v4, sizeof (ip->ia_v4), 541 ip->ia_af, &ret); 542 break; 543 case AF_INET6: 544 he = getipnodebyaddr((char *)&ip->ia_v6, sizeof (ip->ia_v6), 545 ip->ia_af, &ret); 546 break; 547 default: return (ILBADM_INVAL_AF); 548 } 549 550 /* if we can't resolve this, just return an empty name */ 551 if (he == NULL) 552 buf[0] = '\0'; 553 else 554 (void) strlcpy(buf, he->h_name, bufsize); 555 556 return (ILBADM_OK); 557 } 558 559 /* ARGSUSED */ 560 /* 561 * Since this function is used by libilb routine ilb_walk_rules() 562 * it must return libilb errors 563 */ 564 static ilb_status_t 565 ilbadm_show_onerule(ilb_handle_t h, ilb_rule_data_t *rd, void *arg) 566 { 567 ilbadm_sh_rl_arg_t *larg = (ilbadm_sh_rl_arg_t *)arg; 568 ofmt_status_t oerr; 569 int oflags = 0; 570 int ocols = RMAXCOLS; 571 ilbadm_rl_list_arg_t ra; 572 static ofmt_handle_t oh = (ofmt_handle_t)NULL; 573 ofmt_field_t *fields; 574 boolean_t r_enabled = rd->r_flags & ILB_FLAGS_RULE_ENABLED; 575 576 if (larg->o_str == NULL) { 577 ilbadm_err(gettext("internal error")); 578 return (ILB_STATUS_GENERIC); 579 } 580 581 /* 582 * only print rules (enabled/dis-) we're asked to 583 * note: both LIST_**ABLED flags can be set at the same time, 584 * whereas a rule has one state only. therefore the complicated 585 * statement. 586 */ 587 if (!((r_enabled && (larg->flags & ILBADM_LIST_ENABLED)) || 588 (!r_enabled && (larg->flags & ILBADM_LIST_DISABLED)))) 589 return (ILB_STATUS_OK); 590 591 if (larg->flags & ILBADM_LIST_PARSE) 592 oflags |= OFMT_PARSABLE; 593 594 if (larg->flags & ILBADM_LIST_FULL) 595 oflags |= OFMT_MULTILINE; 596 597 bzero(&ra, sizeof (ra)); 598 ra.rd = rd; 599 ra.h = h; 600 601 if (oh == NULL) { 602 if (rd->r_vip.ia_af == AF_INET) 603 fields = rfields_v4; 604 else 605 fields = rfields_v6; 606 607 oerr = ofmt_open(larg->o_str, fields, oflags, ocols, &oh); 608 if (oerr != OFMT_SUCCESS) { 609 char e[80]; 610 611 ilbadm_err(gettext("ofmt_open failed: %s"), 612 ofmt_strerror(oh, oerr, e, sizeof (e))); 613 return (ILB_STATUS_GENERIC); 614 } 615 } 616 617 ofmt_print(oh, &ra); 618 619 return (ILB_STATUS_OK); 620 } 621 622 static char *full_list_rule_hdrs = 623 "RULENAME,STATUS,PORT,PROTOCOL,LBALG,TYPE,PROXY-SRC,PMASK," 624 "HC-NAME,HC-PORT,CONN-DRAIN,NAT-TIMEOUT," 625 "PERSIST-TIMEOUT,SERVERGROUP,VIP,SERVERS"; 626 static char *def_list_rule_hdrs = 627 "RULENAME,STATUS,LBALG,TYPE,PROTOCOL,VIP,PORT"; 628 629 /* ARGSUSED */ 630 ilbadm_status_t 631 ilbadm_show_rules(int argc, char *argv[]) 632 { 633 ilb_handle_t h = ILB_INVALID_HANDLE; 634 int c; 635 ilb_status_t rclib = ILB_STATUS_OK; 636 ilbadm_status_t rc = ILBADM_OK; 637 boolean_t o_opt = B_FALSE, p_opt = B_FALSE; 638 boolean_t f_opt = B_FALSE; 639 ilbadm_sh_rl_arg_t larg = {0, NULL, NULL, NULL}; 640 641 larg.flags = ILBADM_LIST_ENABLED | ILBADM_LIST_DISABLED; 642 while ((c = getopt(argc, argv, ":fpedo:")) != -1) { 643 switch ((char)c) { 644 case 'f': larg.flags |= ILBADM_LIST_FULL; 645 larg.o_str = full_list_rule_hdrs; 646 f_opt = B_TRUE; 647 break; 648 case 'p': larg.flags |= ILBADM_LIST_PARSE; 649 p_opt = B_TRUE; 650 break; 651 case 'o': larg.o_str = optarg; 652 o_opt = B_TRUE; 653 break; 654 /* -e and -d may be repeated - make sure the last one wins */ 655 case 'e': larg.flags &= ILBADM_LIST_NODISABLED; 656 larg.flags |= ILBADM_LIST_ENABLED; 657 break; 658 case 'd': larg.flags &= ILBADM_LIST_NOENABLED; 659 larg.flags |= ILBADM_LIST_DISABLED; 660 break; 661 case ':': ilbadm_err(gettext("missing option argument for %c"), 662 (char)optopt); 663 rc = ILBADM_LIBERR; 664 goto out; 665 /* not reached */ 666 break; 667 case '?': 668 default: 669 unknown_opt(argv, optind-1); 670 /* not reached */ 671 break; 672 } 673 } 674 675 if (f_opt && o_opt) { 676 ilbadm_err(gettext("options -o and -f are mutually" 677 " exclusive")); 678 exit(1); 679 } 680 681 if (p_opt && !o_opt) { 682 ilbadm_err(gettext("option -p requires -o")); 683 exit(1); 684 } 685 686 if (p_opt && larg.o_str != NULL && 687 (strcasecmp(larg.o_str, "all") == 0)) { 688 ilbadm_err(gettext("option -p requires explicit field" 689 " names for -o")); 690 exit(1); 691 } 692 693 /* no -o option, so we use std. fields */ 694 if (!o_opt && !f_opt) 695 larg.o_str = def_list_rule_hdrs; 696 697 rclib = ilb_open(&h); 698 if (rclib != ILB_STATUS_OK) 699 goto out; 700 701 if (optind >= argc) { 702 rclib = ilb_walk_rules(h, ilbadm_show_onerule, NULL, 703 (void*)&larg); 704 } else { 705 while (optind < argc) { 706 rclib = ilb_walk_rules(h, ilbadm_show_onerule, 707 argv[optind++], (void*)&larg); 708 if (rclib != ILB_STATUS_OK) 709 break; 710 } 711 } 712 out: 713 if (h != ILB_INVALID_HANDLE) 714 (void) ilb_close(h); 715 716 if (rclib != ILB_STATUS_OK) { 717 /* 718 * The show function returns ILB_STATUS_GENERIC after printing 719 * out an error message. So we don't need to print it again. 720 */ 721 if (rclib != ILB_STATUS_GENERIC) 722 ilbadm_err(ilb_errstr(rclib)); 723 rc = ILBADM_LIBERR; 724 } 725 return (rc); 726 } 727 728 static boolean_t 729 of_srv2str(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 730 { 731 ilbadm_rl_srvlist_arg_t *larg = 732 (ilbadm_rl_srvlist_arg_t *)of_arg->ofmt_cbarg; 733 ilb_server_data_t *sd = larg->sd; 734 uint_t op = of_arg->ofmt_id; 735 boolean_t ret = B_TRUE; 736 ilbadm_status_t rc; 737 738 if (sd == NULL) 739 return (B_FALSE); 740 741 switch (op) { 742 case OF_SRV_ID: 743 (void) strlcpy(buf, sd->sd_srvID, bufsize); 744 break; 745 case OF_SRV_STATUS: 746 if (ILB_IS_SRV_ENABLED(sd->sd_flags)) 747 buf[0] = 'E'; 748 else 749 buf[0] = 'D'; 750 buf[1] = '\0'; 751 break; 752 case OF_SRV_RNAME: 753 (void) strlcpy(buf, larg->rd->r_name, bufsize); 754 break; 755 case OF_SRV_SGNAME: 756 (void) strlcpy(buf, larg->sgname, bufsize); 757 break; 758 case OF_SRV_HOSTNAME: 759 rc = ip2hostname(&sd->sd_addr, buf, bufsize); 760 if (rc != ILBADM_OK) { 761 buf[0] = '\0'; 762 ret = B_FALSE; 763 } 764 break; 765 case OF_SRV_PORT: 766 ret = of_port2str(sd->sd_minport, sd->sd_maxport, 767 buf, bufsize); 768 break; 769 case OF_SRV_ADDR: 770 ip2str(&sd->sd_addr, buf, bufsize, V6_ADDRONLY); 771 break; 772 } 773 774 return (ret); 775 } 776 777 /* ARGSUSED */ 778 static ilb_status_t 779 i_show_rl_srv(ilb_handle_t h, ilb_server_data_t *sd, const char *sgname, 780 void *arg) 781 { 782 ilbadm_rl_srvlist_arg_t *larg = (ilbadm_rl_srvlist_arg_t *)arg; 783 784 larg->sd = sd; 785 ofmt_print(larg->oh, larg); 786 return (ILB_STATUS_OK); 787 } 788 789 /* ARGSUSED */ 790 /* 791 * Since this function is used by libilb routine ilb_walk_rules() 792 * it must return libilb errors 793 */ 794 ilb_status_t 795 ilbadm_show_rl_servers(ilb_handle_t h, ilb_rule_data_t *rd, void *arg) 796 { 797 ofmt_status_t oerr; 798 int oflags = 0; 799 int ocols = RMAXCOLS; 800 ofmt_field_t *fields; 801 static ofmt_handle_t oh = (ofmt_handle_t)NULL; 802 ilbadm_rl_srvlist_arg_t *larg = (ilbadm_rl_srvlist_arg_t *)arg; 803 804 /* 805 * in full mode, we currently re-open ofmt() for every rule; we use 806 * a variable number of lines, as we print one for every server 807 * attached to a rule. 808 */ 809 if (larg->o_str == NULL) { 810 ilbadm_err(gettext("internal error")); 811 return (ILB_STATUS_GENERIC); 812 } 813 814 if (larg->flags & ILBADM_LIST_PARSE) 815 oflags |= OFMT_PARSABLE; 816 817 if (rd->r_vip.ia_af == AF_INET) 818 fields = ssfields_v4; 819 else 820 fields = ssfields_v6; 821 822 if (oh == NULL) { 823 oerr = ofmt_open(larg->o_str, fields, oflags, ocols, &oh); 824 if (oerr != OFMT_SUCCESS) { 825 char e[80]; 826 827 ilbadm_err(gettext("ofmt_open failed: %s"), 828 ofmt_strerror(oh, oerr, e, sizeof (e))); 829 return (ILB_STATUS_GENERIC); 830 } 831 larg->oh = oh; 832 } 833 834 larg->rd = rd; 835 larg->sgname = rd->r_sgname; 836 837 return (ilb_walk_servers(h, i_show_rl_srv, rd->r_sgname, (void *)larg)); 838 } 839 840 static char *def_show_srv_hdrs = 841 "SERVERID,ADDRESS,PORT,RULENAME,STATUS,SERVERGROUP"; 842 843 /* ARGSUSED */ 844 ilbadm_status_t 845 ilbadm_show_server(int argc, char *argv[]) 846 { 847 ilb_handle_t h = ILB_INVALID_HANDLE; 848 int c; 849 ilb_status_t rclib = ILB_STATUS_OK; 850 ilbadm_status_t rc = ILBADM_OK; 851 boolean_t o_opt = B_FALSE, p_opt = B_FALSE; 852 ilbadm_rl_srvlist_arg_t larg; 853 854 bzero(&larg, sizeof (larg)); 855 while ((c = getopt(argc, argv, ":po:")) != -1) { 856 switch ((char)c) { 857 case 'p': larg.flags |= ILBADM_LIST_PARSE; 858 p_opt = B_TRUE; 859 break; 860 case 'o': larg.o_str = optarg; 861 o_opt = B_TRUE; 862 break; 863 case ':': ilbadm_err(gettext("missing option argument for %c"), 864 (char)optopt); 865 rc = ILBADM_LIBERR; 866 goto out; 867 /* not reached */ 868 break; 869 case '?': 870 default: 871 unknown_opt(argv, optind-1); 872 /* not reached */ 873 break; 874 } 875 } 876 877 if (p_opt && !o_opt) { 878 ilbadm_err(gettext("option -p requires -o")); 879 exit(1); 880 } 881 882 if (p_opt && larg.o_str != NULL && 883 (strcasecmp(larg.o_str, "all") == 0)) { 884 ilbadm_err(gettext("option -p requires explicit" 885 " field names for -o")); 886 exit(1); 887 } 888 889 /* no -o option, so we use default fields */ 890 if (!o_opt) 891 larg.o_str = def_show_srv_hdrs; 892 893 rclib = ilb_open(&h); 894 if (rclib != ILB_STATUS_OK) 895 goto out; 896 897 if (optind >= argc) { 898 rclib = ilb_walk_rules(h, ilbadm_show_rl_servers, NULL, 899 (void*)&larg); 900 } else { 901 while (optind < argc) { 902 rclib = ilb_walk_rules(h, ilbadm_show_rl_servers, 903 argv[optind++], (void*)&larg); 904 if (rclib != ILB_STATUS_OK) 905 break; 906 } 907 } 908 out: 909 if (h != ILB_INVALID_HANDLE) 910 (void) ilb_close(h); 911 912 if (rclib != ILB_STATUS_OK) { 913 /* 914 * The show function returns ILB_STATUS_GENERIC after printing 915 * out an error message. So we don't need to print it again. 916 */ 917 if (rclib != ILB_STATUS_GENERIC) 918 ilbadm_err(ilb_errstr(rclib)); 919 rc = ILBADM_LIBERR; 920 } 921 return (rc); 922 } 923 924 static ilbadm_status_t 925 i_parse_rl_arg(char *arg, ilb_rule_data_t *rd, ilbadm_key_name_t *keylist) 926 { 927 ilbadm_status_t rc; 928 929 rc = i_parse_optstring(arg, (void *) rd, keylist, 930 OPT_PORTS, NULL); 931 return (rc); 932 } 933 934 static void 935 i_ilbadm_alloc_rule(ilb_rule_data_t **rdp) 936 { 937 ilb_rule_data_t *rd; 938 939 *rdp = rd = (ilb_rule_data_t *)calloc(sizeof (*rd), 1); 940 if (rd == NULL) 941 return; 942 rd->r_proto = IPPROTO_TCP; 943 } 944 945 static void 946 i_ilbadm_free_rule(ilb_rule_data_t *rd) 947 { 948 free(rd); 949 } 950 951 /* ARGSUSED */ 952 ilbadm_status_t 953 ilbadm_destroy_rule(int argc, char *argv[]) 954 { 955 ilb_handle_t h = ILB_INVALID_HANDLE; 956 ilbadm_status_t rc = ILBADM_OK; 957 ilb_status_t rclib = ILB_STATUS_OK; 958 boolean_t all_rules = B_FALSE; 959 int c, i; 960 961 while ((c = getopt(argc, argv, ":a")) != -1) { 962 switch ((char)c) { 963 case 'a': 964 all_rules = B_TRUE; 965 break; 966 case '?': 967 default: 968 unknown_opt(argv, optind-1); 969 /* not reached */ 970 break; 971 } 972 } 973 974 if (optind >= argc && !all_rules) { 975 ilbadm_err(gettext("usage: delete-rule -a | name")); 976 return (ILBADM_LIBERR); 977 } 978 979 /* either "-a" or rulename, not both */ 980 if (optind < argc && all_rules) { 981 rc = ILBADM_INVAL_ARGS; 982 goto out; 983 } 984 985 rclib = ilb_open(&h); 986 if (rclib != ILB_STATUS_OK) 987 goto out; 988 989 if (all_rules) { 990 rclib = ilb_destroy_rule(h, NULL); 991 goto out; 992 } 993 994 for (i = optind; i < argc && rclib == ILB_STATUS_OK; i++) 995 rclib = ilb_destroy_rule(h, argv[i]); 996 997 out: 998 if (h != ILB_INVALID_HANDLE) 999 (void) ilb_close(h); 1000 1001 /* This prints the specific errors */ 1002 if (rclib != ILB_STATUS_OK) { 1003 ilbadm_err(ilb_errstr(rclib)); 1004 rc = ILBADM_LIBERR; 1005 } 1006 /* This prints the generic errors */ 1007 if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR)) 1008 ilbadm_err(ilbadm_errstr(rc)); 1009 return (rc); 1010 } 1011 1012 /* ARGSUSED */ 1013 static ilbadm_status_t 1014 ilbadm_Xable_rule(int argc, char *argv[], ilbadm_cmd_t cmd) 1015 { 1016 ilb_handle_t h = ILB_INVALID_HANDLE; 1017 ilb_status_t rclib = ILB_STATUS_OK; 1018 ilbadm_status_t rc = ILBADM_OK; 1019 int i; 1020 1021 rclib = ilb_open(&h); 1022 if (rclib != ILB_STATUS_OK) 1023 goto out; 1024 /* 1025 * by default, en/disable-rule mean "all", and not using 1026 * a rule name will cause this behaviour to kick in 1027 */ 1028 if (argc < 2) { 1029 if (cmd == cmd_enable_rule) 1030 rclib = ilb_enable_rule(h, NULL); 1031 else 1032 rclib = ilb_disable_rule(h, NULL); 1033 } else { 1034 1035 for (i = optind; i < argc && rc == ILBADM_OK; i++) { 1036 if (cmd == cmd_enable_rule) 1037 rclib = ilb_enable_rule(h, argv[i]); 1038 else 1039 rclib = ilb_disable_rule(h, argv[i]); 1040 } 1041 } 1042 out: 1043 if (h != ILB_INVALID_HANDLE) 1044 (void) ilb_close(h); 1045 1046 if (rclib != ILB_STATUS_OK) { 1047 ilbadm_err(ilb_errstr(rclib)); 1048 rc = ILBADM_LIBERR; 1049 } 1050 return (rc); 1051 } 1052 1053 ilbadm_status_t 1054 ilbadm_enable_rule(int argc, char *argv[]) 1055 { 1056 1057 return (ilbadm_Xable_rule(argc, argv, cmd_enable_rule)); 1058 } 1059 1060 ilbadm_status_t 1061 ilbadm_disable_rule(int argc, char *argv[]) 1062 { 1063 return (ilbadm_Xable_rule(argc, argv, cmd_disable_rule)); 1064 } 1065 1066 /* 1067 * parse and create a rule 1068 */ 1069 ilbadm_status_t 1070 ilbadm_create_rule(int argc, char *argv[]) 1071 { 1072 ilb_handle_t h = ILB_INVALID_HANDLE; 1073 int c; 1074 ilb_status_t rclib = ILB_STATUS_OK; 1075 ilbadm_status_t rc = ILBADM_OK; 1076 ilb_rule_data_t *rd; 1077 boolean_t p_opt = B_FALSE; 1078 1079 i_ilbadm_alloc_rule(&rd); 1080 1081 while ((c = getopt(argc, argv, ":ei:m:o:t:h:p")) != -1) { 1082 switch ((char)c) { 1083 case 'e': 1084 rd->r_flags |= ILB_FLAGS_RULE_ENABLED; 1085 break; 1086 case 'h': 1087 /* 1088 * Default value of of r_hcpflag means that if there 1089 * is a port range, probe any port. If there is only 1090 * one port, probe that port. 1091 */ 1092 rd->r_hcpflag = ILB_HCI_PROBE_ANY; 1093 rc = i_parse_rl_arg(optarg, rd, &rl_healthchk_keys[0]); 1094 break; 1095 case 'o': 1096 rc = i_parse_rl_arg(optarg, rd, &rl_outgoing_keys[0]); 1097 break; 1098 case 'm': 1099 rc = i_parse_rl_arg(optarg, rd, &rl_method_keys[0]); 1100 break; 1101 case 't': 1102 rc = i_parse_rl_arg(optarg, rd, &rl_timer_keys[0]); 1103 break; 1104 case 'i': 1105 rc = i_parse_rl_arg(optarg, rd, &rl_incoming_keys[0]); 1106 break; 1107 case 'p': 1108 p_opt = B_TRUE; 1109 break; 1110 case ':': 1111 ilbadm_err(gettext("missing option-argument" 1112 " for %c"), (char)optopt); 1113 rc = ILBADM_LIBERR; 1114 break; 1115 case '?': 1116 default: 1117 unknown_opt(argv, optind-1); 1118 /* not reached */ 1119 break; 1120 1121 } 1122 if (rc != ILBADM_OK) 1123 goto out; 1124 } 1125 1126 if (optind >= argc) { 1127 ilbadm_err(gettext("missing mandatory arguments - please refer" 1128 " to 'ilbadm create-rule' subcommand description in" 1129 " ilbadm(1M)")); 1130 rc = ILBADM_LIBERR; 1131 goto out; 1132 1133 } 1134 1135 if (p_opt) { 1136 /* 1137 * if user hasn't specified a mask, apply default 1138 */ 1139 if ((rd->r_flags & ILB_FLAGS_RULE_STICKY) == 0) { 1140 char *maskstr; 1141 1142 switch (rd->r_vip.ia_af) { 1143 case AF_INET: 1144 maskstr = "32"; 1145 break; 1146 case AF_INET6: 1147 maskstr = "128"; 1148 break; 1149 } 1150 rc = ilbadm_set_netmask(maskstr, &rd->r_stickymask, 1151 rd->r_vip.ia_af); 1152 if (rc != ILBADM_OK) { 1153 ilbadm_err(gettext("trouble seting default" 1154 " persistence mask")); 1155 rc = ILBADM_LIBERR; 1156 goto out; 1157 } 1158 } 1159 } else { 1160 /* use of sticky mask currently mandates "-p" */ 1161 if ((rd->r_flags & ILB_FLAGS_RULE_STICKY) != 0) { 1162 ilbadm_err(gettext("use of stickymask requires" 1163 " -p option")); 1164 rc = ILBADM_LIBERR; 1165 goto out; 1166 } 1167 } 1168 1169 if (strlen(argv[optind]) > ILBD_NAMESZ -1) { 1170 ilbadm_err(gettext("rule name %s is too long -" 1171 " must not exceed %d chars"), argv[optind], 1172 ILBD_NAMESZ - 1); 1173 rc = ILBADM_LIBERR; 1174 goto out; 1175 } 1176 1177 (void) strlcpy(rd->r_name, argv[optind], sizeof (rd->r_name)); 1178 1179 rc = i_check_rule_spec(rd); 1180 if (rc != ILBADM_OK) 1181 goto out; 1182 1183 rclib = ilb_open(&h); 1184 if (rclib != ILB_STATUS_OK) 1185 goto out; 1186 1187 rclib = ilb_create_rule(h, rd); 1188 1189 out: 1190 i_ilbadm_free_rule(rd); 1191 1192 if (h != ILB_INVALID_HANDLE) 1193 (void) ilb_close(h); 1194 1195 if (rclib != ILB_STATUS_OK) { 1196 ilbadm_err(ilb_errstr(rclib)); 1197 rc = ILBADM_LIBERR; 1198 } 1199 if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR)) 1200 ilbadm_err(ilbadm_errstr(rc)); 1201 1202 return (rc); 1203 } 1204 1205 /* ARGSUSED */ 1206 1207 /* 1208 * Since this function is used by libilb function, ilb_walk_rules() 1209 * it must return libilb errors 1210 */ 1211 static ilb_status_t 1212 ilbadm_export_rl(ilb_handle_t h, ilb_rule_data_t *rd, void *arg) 1213 { 1214 char linebuf[128]; /* should be enough */ 1215 int sz = sizeof (linebuf); 1216 FILE *fp = ((ilbadm_rl_exp_arg_t *)arg)->fp; 1217 uint32_t conndrain, nat_timeout, sticky_timeout; 1218 1219 (void) fprintf(fp, "create-rule "); 1220 if (rd->r_flags & ILB_FLAGS_RULE_ENABLED) 1221 (void) fprintf(fp, "-e "); 1222 if (rd->r_flags & ILB_FLAGS_RULE_STICKY) 1223 (void) fprintf(fp, "-p "); 1224 1225 ip2str(&rd->r_vip, linebuf, sz, V6_ADDRONLY); 1226 (void) fprintf(fp, "-i vip=%s,", linebuf); 1227 1228 (void) ports2str(ntohs(rd->r_minport), ntohs(rd->r_maxport), 1229 linebuf, sz); 1230 (void) fprintf(fp, "%s,", linebuf); 1231 1232 proto2str(rd->r_proto, linebuf, sz); 1233 (void) fprintf(fp, "%s ", linebuf); 1234 1235 algo2str(rd->r_algo, linebuf, sz); 1236 (void) fprintf(fp, "-m %s,", linebuf); 1237 1238 topo2str(rd->r_topo, linebuf, sz); 1239 (void) fprintf(fp, "%s", linebuf); 1240 1241 if (rd->r_nat_src_start.ia_af != AF_UNSPEC) { 1242 ip2str(&rd->r_nat_src_start, linebuf, sz, V6_ADDRONLY); 1243 /* if the address is unspecified, skip it */ 1244 if (linebuf[0] != '\0') { 1245 (void) fprintf(fp, ",proxy-src=%s", linebuf); 1246 ip2str(&rd->r_nat_src_end, linebuf, sz, V6_ADDRONLY); 1247 (void) fprintf(fp, "-%s", linebuf); 1248 } 1249 } 1250 1251 if (rd->r_flags & ILB_FLAGS_RULE_STICKY) { 1252 (void) fprintf(fp, ",pmask=/%d", 1253 ilbadm_mask_to_prefixlen(&rd->r_stickymask)); 1254 } 1255 1256 (void) fprintf(fp, " "); 1257 1258 if (*rd->r_hcname != '\0') { 1259 (void) fprintf(fp, "-h hc-name=%s", rd->r_hcname); 1260 hcport_print(rd, linebuf, sizeof (linebuf)); 1261 1262 if (linebuf[0] != '\0') 1263 (void) fprintf(fp, ",hc-port=%s", linebuf); 1264 (void) fprintf(fp, " "); 1265 } 1266 1267 conndrain = rd->r_conndrain; 1268 nat_timeout = rd->r_nat_timeout; 1269 sticky_timeout = rd->r_sticky_timeout; 1270 if (conndrain != 0 || nat_timeout != 0 || sticky_timeout != 0) { 1271 int cnt = 0; 1272 1273 (void) fprintf(fp, "-t "); 1274 if (conndrain != 0) { 1275 cnt++; 1276 (void) fprintf(fp, "conn-drain=%u", conndrain); 1277 } 1278 if (nat_timeout != 0) { 1279 if (cnt > 0) 1280 (void) fprintf(fp, ","); 1281 cnt++; 1282 (void) fprintf(fp, "nat-timeout=%u", nat_timeout); 1283 } 1284 if (sticky_timeout != 0) { 1285 if (cnt > 0) 1286 (void) fprintf(fp, ","); 1287 (void) fprintf(fp, "persist-timeout=%u", 1288 sticky_timeout); 1289 } 1290 (void) fprintf(fp, " "); 1291 } 1292 1293 if (fprintf(fp, "-o servergroup=%s %s\n", rd->r_sgname, rd->r_name) 1294 < 0 || fflush(fp) == EOF) 1295 return (ILB_STATUS_WRITE); 1296 1297 return (ILB_STATUS_OK); 1298 } 1299 1300 ilbadm_status_t 1301 ilbadm_export_rules(ilb_handle_t h, FILE *fp) 1302 { 1303 ilb_status_t rclib; 1304 ilbadm_status_t rc = ILBADM_OK; 1305 ilbadm_rl_exp_arg_t arg; 1306 1307 arg.fp = fp; 1308 1309 rclib = ilb_walk_rules(h, ilbadm_export_rl, NULL, (void *)&arg); 1310 if (rclib != ILB_STATUS_OK) 1311 rc = ILBADM_LIBERR; 1312 return (rc); 1313 } 1314