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