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 <stdlib.h> 28 #include <strings.h> 29 #include <stddef.h> 30 #include <unistd.h> 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <sys/list.h> 36 #include <net/if.h> 37 #include <assert.h> 38 #include <errno.h> 39 #include <libintl.h> 40 #include <libilb.h> 41 #include <inet/ilb.h> 42 #include "libilb_impl.h" 43 #include "ilbd.h" 44 45 /* until we all use AF_* macros ... */ 46 #define AF_2_IPPROTO(_af) (_af == AF_INET)?IPPROTO_IP:IPPROTO_IPV6 47 #define IPPROTO_2_AF(_i) (_i == IPPROTO_IP)?AF_INET:AF_INET6 48 49 static ilb_status_t ilbd_disable_one_rule(ilbd_rule_t *, boolean_t); 50 static uint32_t i_flags_d2k(int); 51 52 #define ILB_SGSRV_2_KSRV(s, k) \ 53 (k)->addr = (s)->sgs_addr; \ 54 (k)->min_port = (s)->sgs_minport; \ 55 (k)->max_port = (s)->sgs_maxport; \ 56 (k)->flags = i_flags_d2k((s)->sgs_flags); \ 57 (k)->err = 0; \ 58 (void) strlcpy((k)->name, (s)->sgs_srvID, sizeof ((k)->name)) 59 60 list_t ilbd_rule_hlist; 61 62 static ilb_algo_t 63 algo_impl2lib(ilb_algo_impl_t a) 64 { 65 switch (a) { 66 case ILB_ALG_IMPL_ROUNDROBIN: 67 return (ILB_ALG_ROUNDROBIN); 68 case ILB_ALG_IMPL_HASH_IP: 69 return (ILB_ALG_HASH_IP); 70 case ILB_ALG_IMPL_HASH_IP_SPORT: 71 return (ILB_ALG_HASH_IP_SPORT); 72 case ILB_ALG_IMPL_HASH_IP_VIP: 73 return (ILB_ALG_HASH_IP_VIP); 74 } 75 return (0); 76 } 77 78 static ilb_topo_t 79 topo_impl2lib(ilb_topo_impl_t t) 80 { 81 switch (t) { 82 case ILB_TOPO_IMPL_DSR: 83 return (ILB_TOPO_DSR); 84 case ILB_TOPO_IMPL_NAT: 85 return (ILB_TOPO_NAT); 86 case ILB_TOPO_IMPL_HALF_NAT: 87 return (ILB_TOPO_HALF_NAT); 88 } 89 return (0); 90 } 91 92 ilb_algo_impl_t 93 algo_lib2impl(ilb_algo_t a) 94 { 95 switch (a) { 96 case ILB_ALG_ROUNDROBIN: 97 return (ILB_ALG_IMPL_ROUNDROBIN); 98 case ILB_ALG_HASH_IP: 99 return (ILB_ALG_IMPL_HASH_IP); 100 case ILB_ALG_HASH_IP_SPORT: 101 return (ILB_ALG_IMPL_HASH_IP_SPORT); 102 case ILB_ALG_HASH_IP_VIP: 103 return (ILB_ALG_IMPL_HASH_IP_VIP); 104 } 105 return (0); 106 } 107 108 ilb_topo_impl_t 109 topo_lib2impl(ilb_topo_t t) 110 { 111 switch (t) { 112 case ILB_TOPO_DSR: 113 return (ILB_TOPO_IMPL_DSR); 114 case ILB_TOPO_NAT: 115 return (ILB_TOPO_IMPL_NAT); 116 case ILB_TOPO_HALF_NAT: 117 return (ILB_TOPO_IMPL_HALF_NAT); 118 } 119 return (0); 120 } 121 122 /* 123 * Walk the list of rules and check if its safe to add the 124 * the server to the rule (this is a list of rules hanging 125 * off of a server group) 126 */ 127 ilb_status_t 128 i_check_srv2rules(list_t *rlist, ilb_sg_srv_t *srv) 129 { 130 ilb_status_t rc = ILB_STATUS_OK; 131 ilbd_rule_t *rl; 132 int server_portrange, rule_portrange; 133 int srv_minport, srv_maxport; 134 int r_minport, r_maxport; 135 136 if (srv == NULL) 137 return (ILB_STATUS_OK); 138 139 srv_minport = ntohs(srv->sgs_minport); 140 srv_maxport = ntohs(srv->sgs_maxport); 141 142 for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) { 143 r_minport = ntohs(rl->irl_minport); 144 r_maxport = ntohs(rl->irl_maxport); 145 146 if ((srv_minport != 0) && (srv_minport == srv_maxport)) { 147 /* server has single port */ 148 if (rl->irl_topo == ILB_TOPO_DSR) { 149 /* 150 * either we have a DSR rule with a port 151 * range, or both server and rule 152 * have single ports but their values 153 * don't match - this is incompatible 154 */ 155 if (r_maxport > r_minport) { 156 rc = ILB_STATUS_INVAL_SRVR; 157 break; 158 } else if (srv_minport != r_minport) { 159 rc = ILB_STATUS_BADPORT; 160 break; 161 } 162 } 163 if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX && 164 rl->irl_hcport != srv_minport) { 165 rc = ILB_STATUS_BADPORT; 166 break; 167 } 168 } else if (srv_maxport > srv_minport) { 169 /* server has a port range */ 170 if ((rl->irl_topo == ILB_TOPO_DSR) && 171 (r_maxport > r_minport)) { 172 if ((r_minport != srv_minport) || 173 (r_maxport != srv_maxport)) { 174 /* 175 * we have a DSR rule with a port range 176 * and its min and max port values 177 * does not meet that of server's 178 * - this is incompatible 179 */ 180 rc = ILB_STATUS_BADPORT; 181 break; 182 } 183 } else if ((rl->irl_topo == ILB_TOPO_DSR) && 184 (r_maxport == r_minport)) { 185 /* 186 * we have a DSR rule with a single 187 * port and a server with a port range 188 * - this is incompatible 189 */ 190 rc = ILB_STATUS_INVAL_SRVR; 191 break; 192 } else if (((rl->irl_topo == ILB_TOPO_NAT) || 193 (rl->irl_topo == ILB_TOPO_HALF_NAT)) && 194 (r_maxport > r_minport)) { 195 server_portrange = srv_maxport - srv_minport; 196 rule_portrange = r_maxport - r_minport; 197 if (rule_portrange != server_portrange) { 198 /* 199 * we have a NAT/Half-NAT rule with 200 * a port range and server with a port 201 * range and there is a mismatch in the 202 * sizes of the port ranges - this is 203 * incompatible 204 */ 205 rc = ILB_STATUS_INVAL_SRVR; 206 break; 207 } 208 } 209 if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX && 210 (rl->irl_hcport > srv_maxport || 211 rl->irl_hcport < srv_minport)) { 212 rc = ILB_STATUS_BADPORT; 213 break; 214 } 215 } 216 } 217 218 return (rc); 219 } 220 221 void 222 i_setup_rule_hlist(void) 223 { 224 list_create(&ilbd_rule_hlist, sizeof (ilbd_rule_t), 225 offsetof(ilbd_rule_t, irl_link)); 226 } 227 228 ilb_status_t 229 i_ilbd_save_rule(ilbd_rule_t *irl, ilbd_scf_cmd_t scf_cmd) 230 { 231 boolean_t enable = irl->irl_flags & ILB_FLAGS_RULE_ENABLED; 232 233 switch (scf_cmd) { 234 case ILBD_SCF_CREATE: 235 return (ilbd_create_pg(ILBD_SCF_RULE, (void *)irl)); 236 case ILBD_SCF_DESTROY: 237 return (ilbd_destroy_pg(ILBD_SCF_RULE, irl->irl_name)); 238 case ILBD_SCF_ENABLE_DISABLE: 239 return (ilbd_change_prop(ILBD_SCF_RULE, irl->irl_name, 240 "status", &enable)); 241 default: 242 logdebug("i_ilbd_save_rule: invalid scf cmd %d", scf_cmd); 243 return (ILB_STATUS_INVAL_CMD); 244 } 245 } 246 247 /* 248 * allocate a new daemon-specific rule from the "template" passed 249 * in in *r 250 */ 251 static ilbd_rule_t * 252 i_alloc_ilbd_rule(ilb_rule_info_t *r) 253 { 254 ilbd_rule_t *rl; 255 256 rl = calloc(sizeof (*rl), 1); 257 if (rl != NULL && r != NULL) 258 bcopy(r, &rl->irl_info, sizeof (*r)); 259 260 return (rl); 261 } 262 263 static ilbd_rule_t * 264 i_find_rule_byname(const char *name) 265 { 266 ilbd_rule_t *rl; 267 268 /* find position of rule in list */ 269 rl = list_head(&ilbd_rule_hlist); 270 while (rl != NULL && 271 strncmp(rl->irl_name, name, sizeof (rl->irl_name)) != 0) { 272 rl = list_next(&ilbd_rule_hlist, rl); 273 } 274 275 return (rl); 276 } 277 278 /* 279 * get exactly one rule (named in rl->irl_name) data from kernel 280 */ 281 static ilb_status_t 282 ilb_get_krule(ilb_rule_info_t *rl) 283 { 284 ilb_status_t rc; 285 ilb_rule_cmd_t kcmd; 286 287 kcmd.cmd = ILB_LIST_RULE; 288 (void) strlcpy(kcmd.name, rl->rl_name, sizeof (kcmd.name)); 289 kcmd.flags = 0; 290 291 rc = do_ioctl(&kcmd, 0); 292 if (rc != ILB_STATUS_OK) 293 return (rc); 294 295 rl->rl_flags = kcmd.flags; 296 rl->rl_ipversion = IPPROTO_2_AF(kcmd.ip_ver); 297 rl->rl_vip = kcmd.vip; 298 rl->rl_proto = kcmd.proto; 299 rl->rl_minport = kcmd.min_port; 300 rl->rl_maxport = kcmd.max_port; 301 rl->rl_algo = algo_impl2lib(kcmd.algo); 302 rl->rl_topo = topo_impl2lib(kcmd.topo); 303 rl->rl_stickymask = kcmd.sticky_mask; 304 rl->rl_nat_src_start = kcmd.nat_src_start; 305 rl->rl_nat_src_end = kcmd.nat_src_end; 306 (void) strlcpy(rl->rl_name, kcmd.name, sizeof (rl->rl_name)); 307 rl->rl_conndrain = kcmd.conn_drain_timeout; 308 rl->rl_nat_timeout = kcmd.nat_expiry; 309 rl->rl_sticky_timeout = kcmd.sticky_expiry; 310 311 return (ILB_STATUS_OK); 312 } 313 314 ilb_status_t 315 ilbd_retrieve_rule(ilbd_name_t rl_name, uint32_t *rbuf, size_t *rbufsz) 316 { 317 ilbd_rule_t *irl = NULL; 318 ilb_status_t rc; 319 ilb_rule_info_t *rinfo; 320 321 irl = i_find_rule_byname(rl_name); 322 if (irl == NULL) 323 return (ILB_STATUS_ENOENT); 324 325 ilbd_reply_ok(rbuf, rbufsz); 326 rinfo = (ilb_rule_info_t *)&((ilb_comm_t *)rbuf)->ic_data; 327 bcopy(&irl->irl_info, rinfo, sizeof (*rinfo)); 328 329 /* 330 * Check if the various timeout values are 0. If one is, get the 331 * default values from kernel. 332 */ 333 if (rinfo->rl_conndrain == 0 || rinfo->rl_nat_timeout == 0 || 334 rinfo->rl_sticky_timeout == 0) { 335 ilb_rule_info_t tmp_info; 336 337 (void) strcpy(tmp_info.rl_name, rinfo->rl_name); 338 rc = ilb_get_krule(&tmp_info); 339 if (rc != ILB_STATUS_OK) 340 return (rc); 341 if (rinfo->rl_conndrain == 0) 342 rinfo->rl_conndrain = tmp_info.rl_conndrain; 343 if ((rinfo->rl_topo == ILB_TOPO_IMPL_NAT || 344 rinfo->rl_topo == ILB_TOPO_IMPL_HALF_NAT) && 345 rinfo->rl_nat_timeout == 0) { 346 rinfo->rl_nat_timeout = tmp_info.rl_nat_timeout; 347 } 348 if ((rinfo->rl_flags & ILB_FLAGS_RULE_STICKY) && 349 rinfo->rl_sticky_timeout == 0) { 350 rinfo->rl_sticky_timeout = tmp_info.rl_sticky_timeout; 351 } 352 } 353 *rbufsz += sizeof (ilb_rule_info_t); 354 355 return (ILB_STATUS_OK); 356 } 357 358 static ilb_status_t 359 ilbd_destroy_one_rule(ilbd_rule_t *irl) 360 { 361 ilb_status_t rc; 362 ilb_name_cmd_t kcmd; 363 364 /* 365 * as far as talking to the kernel is concerned, "all rules" 366 * is handled in one go somewhere else, so we only 367 * tell the kernel about single rules here. 368 */ 369 if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) { 370 kcmd.cmd = ILB_DESTROY_RULE; 371 (void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name)); 372 kcmd.flags = 0; 373 374 rc = do_ioctl(&kcmd, 0); 375 if (rc != ILB_STATUS_OK) 376 return (rc); 377 378 } 379 list_remove(&irl->irl_sg->isg_rulelist, irl); 380 list_remove(&ilbd_rule_hlist, irl); 381 382 /* 383 * When dissociating a rule, only two errors can happen. The hc 384 * name is incorrect or the rule is not associated with the hc 385 * object. Both should not happen.... The check is for debugging 386 * purpose. 387 */ 388 if (RULE_HAS_HC(irl) && (rc = ilbd_hc_dissociate_rule(irl)) != 389 ILB_STATUS_OK) { 390 logerr("ilbd_destroy_one_rule: cannot " 391 "dissociate %s from hc object %s: %d", 392 irl->irl_name, irl->irl_hcname, rc); 393 } 394 395 rc = i_ilbd_save_rule(irl, ILBD_SCF_DESTROY); 396 if (rc != ILB_STATUS_OK) 397 logdebug("ilbd_destroy_rule: save rule failed"); 398 399 free(irl); 400 return (rc); 401 } 402 403 /* 404 * the following two functions are the other's opposite, and can 405 * call into each other for roll back purposes in case of error. 406 * To avoid endless recursion, the 'is_rollback' parameter must be 407 * set to B_TRUE in the roll back case. 408 */ 409 static ilb_status_t 410 ilbd_enable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback) 411 { 412 ilb_status_t rc = ILB_STATUS_OK; 413 ilb_name_cmd_t kcmd; 414 415 /* no use sending a no-op to the kernel */ 416 if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) != 0) 417 return (ILB_STATUS_OK); 418 419 irl->irl_flags |= ILB_FLAGS_RULE_ENABLED; 420 421 /* "all rules" is handled in one go somewhere else, not here */ 422 if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) { 423 kcmd.cmd = ILB_ENABLE_RULE; 424 (void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name)); 425 kcmd.flags = 0; 426 427 rc = do_ioctl(&kcmd, 0); 428 if (rc != ILB_STATUS_OK) 429 return (rc); 430 } 431 if (RULE_HAS_HC(irl) && (rc = ilbd_hc_enable_rule(irl)) != 432 ILB_STATUS_OK) { 433 /* Undo the kernel work */ 434 kcmd.cmd = ILB_DISABLE_RULE; 435 /* Cannot do much if ioctl fails... */ 436 (void) do_ioctl(&kcmd, 0); 437 return (rc); 438 } 439 440 if (!is_rollback) { 441 if (rc == ILB_STATUS_OK) 442 rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE); 443 if (rc != ILB_STATUS_OK) 444 /* ignore rollback return code */ 445 (void) ilbd_disable_one_rule(irl, B_TRUE); 446 } 447 448 return (rc); 449 } 450 451 static ilb_status_t 452 ilbd_disable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback) 453 { 454 ilb_status_t rc = ILB_STATUS_OK; 455 ilb_name_cmd_t kcmd; 456 457 /* no use sending a no-op to the kernel */ 458 if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) == 0) 459 return (ILB_STATUS_OK); 460 461 irl->irl_flags &= ~ILB_FLAGS_RULE_ENABLED; 462 463 /* "all rules" is handled in one go somewhere else, not here */ 464 if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) { 465 kcmd.cmd = ILB_DISABLE_RULE; 466 (void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name)); 467 kcmd.flags = 0; 468 469 rc = do_ioctl(&kcmd, 0); 470 if (rc != ILB_STATUS_OK) 471 return (rc); 472 } 473 474 if (RULE_HAS_HC(irl) && (rc = ilbd_hc_disable_rule(irl)) != 475 ILB_STATUS_OK) { 476 /* Undo the kernel work */ 477 kcmd.cmd = ILB_ENABLE_RULE; 478 /* Cannot do much if ioctl fails... */ 479 (void) do_ioctl(&kcmd, 0); 480 return (rc); 481 } 482 483 if (!is_rollback) { 484 if (rc == ILB_STATUS_OK) 485 rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE); 486 if (rc != ILB_STATUS_OK) 487 /* ignore rollback return code */ 488 (void) ilbd_enable_one_rule(irl, B_TRUE); 489 } 490 491 return (rc); 492 } 493 494 /* 495 * Generates an audit record for a supplied rule name 496 * Used for enable_rule, disable_rule, delete_rule, 497 * and create_rule subcommands 498 */ 499 static void 500 ilbd_audit_rule_event(const char *audit_rule_name, 501 ilb_rule_info_t *rlinfo, ilbd_cmd_t cmd, ilb_status_t rc, 502 ucred_t *ucredp) 503 { 504 adt_session_data_t *ah; 505 adt_event_data_t *event; 506 au_event_t flag; 507 int scf_val_len = ILBD_MAX_VALUE_LEN; 508 char aobuf[scf_val_len]; /* algo:topo */ 509 char pbuf[scf_val_len]; /* protocol */ 510 char pxbuf[scf_val_len]; /* prxy src range */ 511 char hcpbuf[scf_val_len]; /* hcport: num or "ANY" */ 512 char valstr1[scf_val_len]; 513 char valstr2[scf_val_len]; 514 char addrstr_buf[INET6_ADDRSTRLEN]; 515 char addrstr_buf1[INET6_ADDRSTRLEN]; 516 int audit_error; 517 518 if ((ucredp == NULL) && (cmd == ILBD_CREATE_RULE)) { 519 /* 520 * we came here from the path where ilbd incorporates 521 * the configuration that is listed in SCF : 522 * i_ilbd_read_config->ilbd_walk_rule_pgs-> 523 * ->ilbd_scf_instance_walk_pg->ilbd_create_rule 524 * We skip auditing in that case 525 */ 526 return; 527 } 528 if (adt_start_session(&ah, NULL, 0) != 0) { 529 logerr("ilbd_audit_rule_event: adt_start_session failed"); 530 exit(EXIT_FAILURE); 531 } 532 if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) { 533 (void) adt_end_session(ah); 534 logerr("ilbd_audit_rule_event: adt_set_from_ucred failed"); 535 exit(EXIT_FAILURE); 536 } 537 if (cmd == ILBD_ENABLE_RULE) 538 flag = ADT_ilb_enable_rule; 539 else if (cmd == ILBD_DISABLE_RULE) 540 flag = ADT_ilb_disable_rule; 541 else if (cmd == ILBD_DESTROY_RULE) 542 flag = ADT_ilb_delete_rule; 543 else if (cmd == ILBD_CREATE_RULE) 544 flag = ADT_ilb_create_rule; 545 546 if ((event = adt_alloc_event(ah, flag)) == NULL) { 547 logerr("ilbd_audit_rule_event: adt_alloc_event failed"); 548 exit(EXIT_FAILURE); 549 } 550 551 (void) memset((char *)event, 0, sizeof (adt_event_data_t)); 552 553 switch (cmd) { 554 case ILBD_DESTROY_RULE: 555 event->adt_ilb_delete_rule.auth_used = NET_ILB_CONFIG_AUTH; 556 event->adt_ilb_delete_rule.rule_name = (char *)audit_rule_name; 557 break; 558 case ILBD_ENABLE_RULE: 559 event->adt_ilb_enable_rule.auth_used = NET_ILB_ENABLE_AUTH; 560 event->adt_ilb_enable_rule.rule_name = (char *)audit_rule_name; 561 break; 562 case ILBD_DISABLE_RULE: 563 event->adt_ilb_disable_rule.auth_used = NET_ILB_ENABLE_AUTH; 564 event->adt_ilb_disable_rule.rule_name = (char *)audit_rule_name; 565 break; 566 case ILBD_CREATE_RULE: 567 aobuf[0] = '\0'; 568 pbuf[0] = '\0'; 569 valstr1[0] = '\0'; 570 valstr2[0] = '\0'; 571 hcpbuf[0] = '\0'; 572 573 event->adt_ilb_create_rule.auth_used = NET_ILB_CONFIG_AUTH; 574 575 /* Fill in virtual IP address */ 576 addrstr_buf[0] = '\0'; 577 ilbd_addr2str(&rlinfo->rl_vip, addrstr_buf, 578 sizeof (addrstr_buf)); 579 event->adt_ilb_create_rule.virtual_ipaddress = addrstr_buf; 580 581 /* Fill in port - could be a single value or a range */ 582 event->adt_ilb_create_rule.min_port = ntohs(rlinfo->rl_minport); 583 if (ntohs(rlinfo->rl_maxport) > ntohs(rlinfo->rl_minport)) { 584 /* port range */ 585 event->adt_ilb_create_rule.max_port = 586 ntohs(rlinfo->rl_maxport); 587 } else { 588 /* in audit record, max=min when single port */ 589 event->adt_ilb_create_rule.max_port = 590 ntohs(rlinfo->rl_minport); 591 } 592 593 /* 594 * Fill in protocol - if user does not specify it, 595 * its TCP by default 596 */ 597 if (rlinfo->rl_proto == IPPROTO_UDP) 598 (void) snprintf(pbuf, sizeof (pbuf), "UDP"); 599 else 600 (void) snprintf(pbuf, sizeof (pbuf), "TCP"); 601 event->adt_ilb_create_rule.protocol = pbuf; 602 603 /* Fill in algorithm and operation type */ 604 ilbd_algo_to_str(rlinfo->rl_algo, valstr1); 605 ilbd_topo_to_str(rlinfo->rl_topo, valstr2); 606 (void) snprintf(aobuf, sizeof (aobuf), "%s:%s", 607 valstr1, valstr2); 608 event->adt_ilb_create_rule.algo_optype = aobuf; 609 610 /* Fill in proxy-src for the NAT case */ 611 if (rlinfo->rl_topo == ILB_TOPO_NAT) { 612 ilbd_addr2str(&rlinfo->rl_nat_src_start, addrstr_buf, 613 sizeof (addrstr_buf)); 614 if (&rlinfo->rl_nat_src_end == 0) { 615 /* Single address */ 616 (void) snprintf(pxbuf, sizeof (pxbuf), 617 "%s", addrstr_buf); 618 } else { 619 /* address range */ 620 ilbd_addr2str(&rlinfo->rl_nat_src_end, 621 addrstr_buf1, sizeof (addrstr_buf1)); 622 (void) snprintf(pxbuf, sizeof (pxbuf), 623 "%s-%s", addrstr_buf, addrstr_buf1); 624 } 625 event->adt_ilb_create_rule.proxy_src = pxbuf; 626 } 627 628 /* 629 * Fill in pmask if user has specified one - 0 means 630 * no persistence 631 */ 632 valstr1[0] = '\0'; 633 ilbd_ip_to_str(rlinfo->rl_ipversion, &rlinfo->rl_stickymask, 634 valstr1); 635 event->adt_ilb_create_rule.persist_mask = valstr1; 636 637 /* If there is a hcname */ 638 if (rlinfo->rl_hcname[0] != '\0') 639 event->adt_ilb_create_rule.hcname = rlinfo->rl_hcname; 640 641 /* Fill in hcport */ 642 if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_FIX) { 643 /* hcport is specified by user */ 644 (void) snprintf(hcpbuf, sizeof (hcpbuf), "%d", 645 rlinfo->rl_hcport); 646 event->adt_ilb_create_rule.hcport = hcpbuf; 647 } else if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_ANY) { 648 /* user has specified "ANY" */ 649 (void) snprintf(hcpbuf, sizeof (hcpbuf), "ANY"); 650 event->adt_ilb_create_rule.hcport = hcpbuf; 651 } 652 653 /* 654 * Fill out the conndrain, nat_timeout and persist_timeout 655 * If the user does not specify them, the default value 656 * is set in the kernel. Userland does not know what 657 * the values are. So if the user 658 * does not specify these values they will show up as 659 * 0 in the audit record. 660 */ 661 event->adt_ilb_create_rule.conndrain_timeout = 662 rlinfo->rl_conndrain; 663 event->adt_ilb_create_rule.nat_timeout = 664 rlinfo->rl_nat_timeout; 665 event->adt_ilb_create_rule.persist_timeout = 666 rlinfo->rl_sticky_timeout; 667 668 /* Fill out servergroup and rule name */ 669 event->adt_ilb_create_rule.server_group = rlinfo->rl_sgname; 670 event->adt_ilb_create_rule.rule_name = rlinfo->rl_name; 671 break; 672 } 673 if (rc == ILB_STATUS_OK) { 674 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 675 logerr("ilbd_audit_rule_event:adt_put_event failed"); 676 exit(EXIT_FAILURE); 677 } 678 } else { 679 audit_error = ilberror2auditerror(rc); 680 if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) { 681 logerr("ilbd_audit_rule_event: adt_put_event failed"); 682 exit(EXIT_FAILURE); 683 } 684 } 685 adt_free_event(event); 686 (void) adt_end_session(ah); 687 } 688 689 static ilb_status_t 690 i_ilbd_action_switch(ilbd_rule_t *irl, ilbd_cmd_t cmd, 691 boolean_t is_rollback, ucred_t *ucredp) 692 { 693 ilb_status_t rc; 694 695 switch (cmd) { 696 case ILBD_DESTROY_RULE: 697 rc = ilbd_destroy_one_rule(irl); 698 if (!is_rollback) { 699 ilbd_audit_rule_event(irl->irl_name, NULL, 700 cmd, rc, ucredp); 701 } 702 return (rc); 703 case ILBD_ENABLE_RULE: 704 rc = ilbd_enable_one_rule(irl, is_rollback); 705 if (!is_rollback) { 706 ilbd_audit_rule_event(irl->irl_name, NULL, cmd, 707 rc, ucredp); 708 } 709 return (rc); 710 case ILBD_DISABLE_RULE: 711 rc = ilbd_disable_one_rule(irl, is_rollback); 712 if (!is_rollback) { 713 ilbd_audit_rule_event(irl->irl_name, NULL, cmd, 714 rc, ucredp); 715 } 716 return (rc); 717 } 718 return (ILB_STATUS_INVAL_CMD); 719 } 720 721 static ilb_cmd_t 722 i_ilbd2ilb_cmd(ilbd_cmd_t c) 723 { 724 ilb_cmd_t r; 725 726 switch (c) { 727 case ILBD_CREATE_RULE: 728 r = ILB_CREATE_RULE; 729 break; 730 case ILBD_DESTROY_RULE: 731 r = ILB_DESTROY_RULE; 732 break; 733 case ILBD_ENABLE_RULE: 734 r = ILB_ENABLE_RULE; 735 break; 736 case ILBD_DISABLE_RULE: 737 r = ILB_DISABLE_RULE; 738 break; 739 } 740 return (r); 741 } 742 743 static ilbd_cmd_t 744 get_undo_cmd(ilbd_cmd_t cmd) 745 { 746 ilbd_cmd_t u_cmd; 747 748 switch (cmd) { 749 case ILBD_DESTROY_RULE: 750 u_cmd = ILBD_BAD_CMD; 751 break; 752 case ILBD_ENABLE_RULE: 753 u_cmd = ILBD_DISABLE_RULE; 754 break; 755 case ILBD_DISABLE_RULE: 756 u_cmd = ILBD_ENABLE_RULE; 757 break; 758 } 759 760 return (u_cmd); 761 } 762 763 static ilb_status_t 764 i_ilbd_rule_action(const char *rule_name, const struct passwd *ps, 765 ilbd_cmd_t cmd, ucred_t *ucredp) 766 { 767 ilbd_rule_t *irl, *irl_next; 768 boolean_t is_all_rules = B_FALSE; 769 ilb_status_t rc = ILB_STATUS_OK; 770 ilb_name_cmd_t kcmd; 771 ilbd_cmd_t u_cmd; 772 char rulename[ILB_NAMESZ]; 773 774 if (ps != NULL) { 775 if ((cmd == ILBD_ENABLE_RULE) || (cmd == ILBD_DISABLE_RULE)) 776 rc = ilbd_check_client_enable_auth(ps); 777 else 778 rc = ilbd_check_client_config_auth(ps); 779 /* generate the audit record before bailing out */ 780 if (rc != ILB_STATUS_OK) { 781 if (rule_name != '\0') { 782 ilbd_audit_rule_event(rule_name, NULL, 783 cmd, rc, ucredp); 784 } else { 785 (void) snprintf(rulename, sizeof (rulename), 786 "all"); 787 ilbd_audit_rule_event(rulename, NULL, cmd, rc, 788 ucredp); 789 } 790 goto out; 791 } 792 } 793 is_all_rules = rule_name[0] == 0; 794 795 /* just one rule */ 796 if (!is_all_rules) { 797 irl = i_find_rule_byname(rule_name); 798 if (irl == NULL) { 799 rc = ILB_STATUS_ENORULE; 800 ilbd_audit_rule_event(rule_name, NULL, cmd, rc, ucredp); 801 goto out; 802 } 803 /* auditing will be done by i_ilbd_action_switch() */ 804 rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp); 805 goto out; 806 } 807 808 /* all rules: first tell the kernel, then walk the daemon's list */ 809 kcmd.cmd = i_ilbd2ilb_cmd(cmd); 810 kcmd.flags = ILB_RULE_ALLRULES; 811 812 rc = do_ioctl(&kcmd, 0); 813 if (rc != ILB_STATUS_OK) { 814 (void) snprintf(rulename, sizeof (rulename), "all"); 815 ilbd_audit_rule_event(rulename, NULL, cmd, rc, ucredp); 816 goto out; 817 } 818 819 irl = list_head(&ilbd_rule_hlist); 820 while (irl != NULL) { 821 irl_next = list_next(&ilbd_rule_hlist, irl); 822 irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES; 823 /* auditing will be done by i_ilbd_action_switch() */ 824 rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp); 825 irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES; 826 if (rc != ILB_STATUS_OK) 827 goto rollback_list; 828 irl = irl_next; 829 } 830 return (rc); 831 832 rollback_list: 833 u_cmd = get_undo_cmd(cmd); 834 if (u_cmd == ILBD_BAD_CMD) 835 return (rc); 836 837 if (is_all_rules) { 838 kcmd.cmd = i_ilbd2ilb_cmd(u_cmd); 839 (void) do_ioctl(&kcmd, 0); 840 } 841 /* current list element failed, so we start with previous one */ 842 irl = list_prev(&ilbd_rule_hlist, irl); 843 while (irl != NULL) { 844 if (is_all_rules) 845 irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES; 846 847 /* 848 * When the processing of a command consists of 849 * multiple sequential steps, and one of them fails, 850 * ilbd performs rollback to undo the steps taken before the 851 * failing step. Since ilbd is initiating these steps 852 * there is not need to audit them. 853 */ 854 rc = i_ilbd_action_switch(irl, u_cmd, B_TRUE, NULL); 855 irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES; 856 857 irl = list_prev(&ilbd_rule_hlist, irl); 858 } 859 out: 860 return (rc); 861 } 862 863 ilb_status_t 864 ilbd_destroy_rule(ilbd_name_t rule_name, const struct passwd *ps, 865 ucred_t *ucredp) 866 { 867 return (i_ilbd_rule_action(rule_name, ps, ILBD_DESTROY_RULE, ucredp)); 868 } 869 870 ilb_status_t 871 ilbd_enable_rule(ilbd_name_t rule_name, const struct passwd *ps, 872 ucred_t *ucredp) 873 { 874 return (i_ilbd_rule_action(rule_name, ps, ILBD_ENABLE_RULE, ucredp)); 875 876 } 877 878 ilb_status_t 879 ilbd_disable_rule(ilbd_name_t rule_name, const struct passwd *ps, 880 ucred_t *ucredp) 881 { 882 return (i_ilbd_rule_action(rule_name, ps, ILBD_DISABLE_RULE, ucredp)); 883 } 884 885 /* 886 * allocate storage for a kernel rule command and fill from 887 * "template" irl, if non-NULL 888 */ 889 static ilb_rule_cmd_t * 890 i_alloc_kernel_rule_cmd(ilbd_rule_t *irl) 891 { 892 ilb_rule_cmd_t *kcmd; 893 894 kcmd = (ilb_rule_cmd_t *)malloc(sizeof (*kcmd)); 895 if (kcmd == NULL) 896 return (kcmd); 897 898 bzero(kcmd, sizeof (*kcmd)); 899 900 if (irl != NULL) { 901 kcmd->flags = irl->irl_flags; 902 kcmd->ip_ver = AF_2_IPPROTO(irl->irl_ipversion); 903 kcmd->vip = irl->irl_vip; 904 kcmd->proto = irl->irl_proto; 905 kcmd->min_port = irl->irl_minport; 906 kcmd->max_port = irl->irl_maxport; 907 kcmd->algo = algo_lib2impl(irl->irl_algo); 908 kcmd->topo = topo_lib2impl(irl->irl_topo); 909 kcmd->sticky_mask = irl->irl_stickymask; 910 kcmd->nat_src_start = irl->irl_nat_src_start; 911 kcmd->nat_src_end = irl->irl_nat_src_end; 912 kcmd->conn_drain_timeout = irl->irl_conndrain; 913 kcmd->nat_expiry = irl->irl_nat_timeout; 914 kcmd->sticky_expiry = irl->irl_sticky_timeout; 915 (void) strlcpy(kcmd->name, irl->irl_name, 916 sizeof (kcmd->name)); 917 } 918 return (kcmd); 919 } 920 921 /* 922 * ncount is the next to be used index into (*kcmdp)->servers 923 */ 924 static ilb_status_t 925 adjust_srv_info_cmd(ilb_servers_info_cmd_t **kcmdp, int index) 926 { 927 ilb_servers_info_cmd_t *kcmd = *kcmdp; 928 size_t sz; 929 930 if (kcmd != NULL && kcmd->num_servers > index + 1) 931 return (ILB_STATUS_OK); 932 933 /* 934 * the first ilb_server_info_t is part of *kcmd, so 935 * by using index (which is one less than the total needed) here, 936 * we allocate exactly the amount we need. 937 */ 938 sz = sizeof (*kcmd) + (index * sizeof (ilb_server_info_t)); 939 kcmd = (ilb_servers_info_cmd_t *)realloc(kcmd, sz); 940 if (kcmd == NULL) 941 return (ILB_STATUS_ENOMEM); 942 943 /* 944 * we don't count the slot we newly allocated yet. 945 */ 946 kcmd->num_servers = index; 947 *kcmdp = kcmd; 948 949 return (ILB_STATUS_OK); 950 } 951 952 /* 953 * this function adds all servers in srvlist to the kernel(!) rule 954 * the name of which is passed as argument. 955 */ 956 static ilb_status_t 957 i_update_ksrv_rules(char *name, ilbd_sg_t *sg, ilbd_rule_t *rl) 958 { 959 ilb_status_t rc; 960 ilbd_srv_t *srvp; 961 ilb_servers_info_cmd_t *kcmd = NULL; 962 int i; 963 964 /* 965 * If the servergroup doesn't have any servers associated with 966 * it yet, there's nothing more to do here. 967 */ 968 if (sg->isg_srvcount == 0) 969 return (ILB_STATUS_OK); 970 971 /* 972 * walk the list of servers attached to this SG 973 */ 974 srvp = list_head(&sg->isg_srvlist); 975 for (i = 0; srvp != NULL; srvp = list_next(&sg->isg_srvlist, srvp)) { 976 rc = adjust_srv_info_cmd(&kcmd, i); 977 if (rc != ILB_STATUS_OK) 978 return (rc); 979 980 ILB_SGSRV_2_KSRV(&srvp->isv_srv, &kcmd->servers[i]); 981 /* 982 * "no port" means "copy rule's port" (for kernel rule) 983 */ 984 if (kcmd->servers[i].min_port == 0) { 985 kcmd->servers[i].min_port = rl->irl_minport; 986 kcmd->servers[i].max_port = rl->irl_maxport; 987 } 988 i++; 989 } 990 991 kcmd->cmd = ILB_ADD_SERVERS; 992 kcmd->num_servers = i; 993 (void) strlcpy(kcmd->name, name, sizeof (kcmd->name)); 994 995 rc = do_ioctl(kcmd, 0); 996 if (rc != ILB_STATUS_OK) 997 return (rc); 998 999 for (i = 0; i < kcmd->num_servers; i++) { 1000 int e; 1001 1002 if ((e = kcmd->servers[i].err) != 0) { 1003 logerr("i_update_ksrv_rules " 1004 "ioctl indicates failure: %s", strerror(e)); 1005 rc = ilb_map_errno2ilbstat(e); 1006 /* 1007 * if adding even a single server failed, we need to 1008 * roll back the whole wad. We ignore any errors and 1009 * return the one that was returned by the first ioctl. 1010 */ 1011 kcmd->cmd = ILB_DEL_SERVERS; 1012 (void) do_ioctl(kcmd, 0); 1013 return (rc); 1014 } 1015 } 1016 1017 return (ILB_STATUS_OK); 1018 } 1019 1020 /* convert a struct in6_addr to valstr */ 1021 void 1022 ilbd_ip_to_str(uint16_t ipversion, struct in6_addr *addr, char *valstr) 1023 { 1024 size_t vallen; 1025 ilb_ip_addr_t ipaddr; 1026 void *addrptr; 1027 1028 vallen = (ipversion == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; 1029 1030 IP_COPY_IMPL_2_CLI(addr, &ipaddr); 1031 addrptr = (ipversion == AF_INET) ? 1032 (void *)&ipaddr.ia_v4 : (void *)&ipaddr.ia_v6; 1033 if (inet_ntop(ipversion, (void *)addrptr, valstr, vallen == NULL)) 1034 logerr("ilbd_ip_to_str: inet_ntop failed"); 1035 return; 1036 1037 } 1038 1039 ilb_status_t 1040 ilbd_create_rule(ilb_rule_info_t *rl, int ev_port, 1041 const struct passwd *ps, ucred_t *ucredp) 1042 { 1043 ilb_status_t rc; 1044 ilbd_rule_t *irl = NULL; 1045 ilbd_sg_t *sg; 1046 ilb_rule_cmd_t *kcmd = NULL; 1047 1048 if (ps != NULL) { 1049 if ((rc = ilbd_check_client_config_auth(ps)) != ILB_STATUS_OK) 1050 goto out; 1051 } 1052 1053 if (i_find_rule_byname(rl->rl_name) != NULL) { 1054 logdebug("ilbd_create_rule: rule %s" 1055 " already exists", rl->rl_name); 1056 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1057 ILB_STATUS_DUP_RULE, ucredp); 1058 return (ILB_STATUS_DUP_RULE); 1059 } 1060 1061 sg = i_find_sg_byname(rl->rl_sgname); 1062 if (sg == NULL) { 1063 logdebug("ilbd_create_rule: rule %s uses non-existent" 1064 " servergroup name %s", rl->rl_name, rl->rl_sgname); 1065 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1066 ILB_STATUS_SGUNAVAIL, ucredp); 1067 return (ILB_STATUS_SGUNAVAIL); 1068 } 1069 1070 if ((rc = ilbd_sg_check_rule_port(sg, rl)) != ILB_STATUS_OK) { 1071 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp); 1072 return (rc); 1073 } 1074 1075 /* allocs and copies contents of arg (if != NULL) into new rule */ 1076 irl = i_alloc_ilbd_rule(rl); 1077 if (irl == NULL) { 1078 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1079 ILB_STATUS_ENOMEM, ucredp); 1080 return (ILB_STATUS_ENOMEM); 1081 } 1082 1083 /* make sure rule's IPversion (via vip) and SG's match */ 1084 if (sg->isg_srvcount > 0) { 1085 ilbd_srv_t *srv = list_head(&sg->isg_srvlist); 1086 int32_t r_af = rl->rl_ipversion; 1087 int32_t s_af = GET_AF(&srv->isv_addr); 1088 1089 if (r_af != s_af) { 1090 logdebug("address family mismatch with servergroup"); 1091 rc = ILB_STATUS_MISMATCHSG; 1092 goto out; 1093 } 1094 } 1095 irl->irl_sg = sg; 1096 1097 /* Try associating the rule with the given hc oject. */ 1098 if (RULE_HAS_HC(irl)) { 1099 if ((rc = ilbd_hc_associate_rule(irl, ev_port)) != 1100 ILB_STATUS_OK) 1101 goto out; 1102 } 1103 1104 /* 1105 * checks are done, now: 1106 * 1. create rule in kernel 1107 * 2. tell it about the backend server (which we maintain in SG) 1108 * 3. attach the rule in memory 1109 */ 1110 /* 1. */ 1111 /* allocs and copies contents of arg (if != NULL) into new rule */ 1112 kcmd = i_alloc_kernel_rule_cmd(irl); 1113 if (kcmd == NULL) { 1114 rc = ILB_STATUS_ENOMEM; 1115 goto rollback_hc; 1116 } 1117 kcmd->cmd = ILB_CREATE_RULE; 1118 1119 rc = do_ioctl(kcmd, 0); 1120 if (rc != ILB_STATUS_OK) 1121 goto rollback_kcmd; 1122 1123 /* 2. */ 1124 rc = i_update_ksrv_rules(kcmd->name, sg, irl); 1125 if (rc != ILB_STATUS_OK) 1126 goto rollback_kcmd; 1127 1128 /* 3. */ 1129 (void) i_attach_rule2sg(sg, irl); 1130 list_insert_tail(&ilbd_rule_hlist, irl); 1131 1132 if (ps != NULL) { 1133 rc = i_ilbd_save_rule(irl, ILBD_SCF_CREATE); 1134 if (rc != ILB_STATUS_OK) 1135 goto rollback_rule; 1136 } 1137 1138 free(kcmd); 1139 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1140 ILB_STATUS_OK, ucredp); 1141 return (ILB_STATUS_OK); 1142 1143 rollback_rule: 1144 /* 1145 * ilbd_destroy_one_rule() also frees irl, as well as dissociate 1146 * rule and HC, so all we need to do afterwards is free the kcmd 1147 * and return. 1148 */ 1149 (void) ilbd_destroy_one_rule(irl); 1150 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp); 1151 free(kcmd); 1152 return (rc); 1153 1154 rollback_kcmd: 1155 free(kcmd); 1156 rollback_hc: 1157 /* Cannot fail since the rule is just associated with the hc object. */ 1158 if (RULE_HAS_HC(irl)) 1159 (void) ilbd_hc_dissociate_rule(irl); 1160 out: 1161 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp); 1162 free(irl); 1163 return (rc); 1164 } 1165 1166 static uint32_t 1167 i_flags_d2k(int f) 1168 { 1169 uint32_t r = 0; 1170 1171 if (ILB_IS_SRV_ENABLED(f)) 1172 r |= ILB_SERVER_ENABLED; 1173 /* more as they are defined */ 1174 1175 return (r); 1176 } 1177 1178 /* 1179 * walk the list of rules and add srv to the *kernel* rule 1180 * (this is a list of rules hanging off of a server group) 1181 */ 1182 ilb_status_t 1183 i_add_srv2krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port) 1184 { 1185 ilb_status_t rc = ILB_STATUS_OK; 1186 ilbd_rule_t *rl, *del_rl; 1187 ilb_servers_info_cmd_t kcmd; 1188 ilb_servers_cmd_t del_kcmd; 1189 1190 kcmd.cmd = ILB_ADD_SERVERS; 1191 kcmd.num_servers = 1; 1192 kcmd.servers[0].err = 0; 1193 kcmd.servers[0].addr = srv->sgs_addr; 1194 kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags); 1195 (void) strlcpy(kcmd.servers[0].name, srv->sgs_srvID, 1196 sizeof (kcmd.servers[0].name)); 1197 1198 /* 1199 * a note about rollback: since we need to start rollback with the 1200 * current list element in some case, and with the previous one 1201 * in others, we must "go back" in this latter case before 1202 * we jump to the rollback code. 1203 */ 1204 for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) { 1205 (void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name)); 1206 /* 1207 * sgs_minport == 0 means "no port specified"; this 1208 * indicates that the server matches anything the rule 1209 * provides. 1210 * NOTE: this can be different for different rules 1211 * using the same server group, therefore we don't modify 1212 * this information in the servergroup, but *only* in 1213 * the kernel's rule. 1214 */ 1215 if (srv->sgs_minport == 0) { 1216 kcmd.servers[0].min_port = rl->irl_minport; 1217 kcmd.servers[0].max_port = rl->irl_maxport; 1218 } else { 1219 kcmd.servers[0].min_port = srv->sgs_minport; 1220 kcmd.servers[0].max_port = srv->sgs_maxport; 1221 } 1222 rc = do_ioctl((void *)&kcmd, 0); 1223 if (rc != ILB_STATUS_OK) { 1224 logdebug("i_add_srv2krules: do_ioctl call failed"); 1225 del_rl = list_prev(rlist, rl); 1226 goto rollback; 1227 } 1228 1229 /* 1230 * if ioctl() returns != 0, it doesn't perform the copyout 1231 * necessary to indicate *which* server failed (we could be 1232 * adding more than one); therefore we must check this 1233 * 'err' field even if ioctl() returns 0. 1234 */ 1235 if (kcmd.servers[0].err != 0) { 1236 logerr("i_add_srv2krules: SIOCILB ioctl returned" 1237 " error %d", kcmd.servers[0].err); 1238 rc = ilb_map_errno2ilbstat(kcmd.servers[0].err); 1239 del_rl = list_prev(rlist, rl); 1240 goto rollback; 1241 } 1242 if (RULE_HAS_HC(rl)) { 1243 if ((rc = ilbd_hc_add_server(rl, srv, ev_port)) != 1244 ILB_STATUS_OK) { 1245 logerr("i_add_srv2krules: cannot start timer " 1246 " for rules %s server %s", rl->irl_name, 1247 srv->sgs_srvID); 1248 1249 del_rl = rl; 1250 goto rollback; 1251 } 1252 } 1253 } 1254 1255 return (rc); 1256 1257 rollback: 1258 /* 1259 * this is almost, but not quite, the same as i_rem_srv_frm_krules() 1260 * therefore we keep it seperate. 1261 */ 1262 del_kcmd.cmd = ILB_DEL_SERVERS; 1263 del_kcmd.num_servers = 1; 1264 del_kcmd.servers[0].addr = srv->sgs_addr; 1265 while (del_rl != NULL) { 1266 if (RULE_HAS_HC(del_rl)) 1267 (void) ilbd_hc_del_server(del_rl, srv); 1268 (void) strlcpy(del_kcmd.name, del_rl->irl_name, 1269 sizeof (del_kcmd.name)); 1270 (void) do_ioctl((void *)&del_kcmd, 0); 1271 del_rl = list_prev(rlist, del_rl); 1272 } 1273 1274 return (rc); 1275 } 1276 1277 /* 1278 * ev_port is only used for rollback purposes in this function 1279 */ 1280 ilb_status_t 1281 i_rem_srv_frm_krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port) 1282 { 1283 ilb_status_t rc = ILB_STATUS_OK; 1284 ilbd_rule_t *rl, *add_rl; 1285 ilb_servers_cmd_t kcmd; 1286 ilb_servers_info_cmd_t add_kcmd; 1287 1288 kcmd.cmd = ILB_DEL_SERVERS; 1289 kcmd.num_servers = 1; 1290 kcmd.servers[0].err = 0; 1291 kcmd.servers[0].addr = srv->sgs_addr; 1292 1293 for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) { 1294 (void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name)); 1295 rc = do_ioctl((void *)&kcmd, 0); 1296 if (rc != ILB_STATUS_OK) { 1297 logdebug("i_rem_srv_frm_krules: do_ioctl" 1298 "call failed"); 1299 add_rl = list_prev(rlist, rl); 1300 goto rollback; 1301 } 1302 /* 1303 * if ioctl() returns != 0, it doesn't perform the copyout 1304 * necessary to indicate *which* server failed (we could be 1305 * removing more than one); therefore we must check this 1306 * 'err' field even if ioctl() returns 0. 1307 */ 1308 if (kcmd.servers[0].err != 0) { 1309 logerr("i_rem_srv_frm_krules: SIOCILB ioctl" 1310 " returned error %s", 1311 strerror(kcmd.servers[0].err)); 1312 rc = ilb_map_errno2ilbstat(kcmd.servers[0].err); 1313 add_rl = list_prev(rlist, rl); 1314 goto rollback; 1315 } 1316 if (RULE_HAS_HC(rl) && 1317 (rc = ilbd_hc_del_server(rl, srv)) != ILB_STATUS_OK) { 1318 logerr("i_rem_srv_frm_krules: cannot delete " 1319 "timer for rules %s server %s", rl->irl_name, 1320 srv->sgs_srvID); 1321 add_rl = rl; 1322 goto rollback; 1323 } 1324 } 1325 1326 return (rc); 1327 1328 rollback: 1329 /* Don't do roll back if ev_port == -1. */ 1330 if (ev_port == -1) 1331 return (rc); 1332 1333 add_kcmd.cmd = ILB_ADD_SERVERS; 1334 add_kcmd.num_servers = 1; 1335 add_kcmd.servers[0].err = 0; 1336 add_kcmd.servers[0].addr = srv->sgs_addr; 1337 add_kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags); 1338 (void) strlcpy(add_kcmd.servers[0].name, srv->sgs_srvID, 1339 sizeof (add_kcmd.servers[0].name)); 1340 while (add_rl != NULL) { 1341 if (srv->sgs_minport == 0) { 1342 add_kcmd.servers[0].min_port = add_rl->irl_minport; 1343 add_kcmd.servers[0].max_port = add_rl->irl_maxport; 1344 } else { 1345 add_kcmd.servers[0].min_port = srv->sgs_minport; 1346 add_kcmd.servers[0].max_port = srv->sgs_maxport; 1347 } 1348 if (RULE_HAS_HC(add_rl)) 1349 (void) ilbd_hc_add_server(add_rl, srv, ev_port); 1350 (void) strlcpy(add_kcmd.name, add_rl->irl_name, 1351 sizeof (add_kcmd.name)); 1352 (void) do_ioctl((void *)&add_kcmd, 0); 1353 add_rl = list_prev(rlist, add_rl); 1354 } 1355 1356 return (rc); 1357 } 1358