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