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 <sys/types.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <stddef.h> 33 #include <libilb_impl.h> 34 #include <libilb.h> 35 36 static ilb_status_t 37 i_ilb_addrem_sg(ilb_handle_t h, const char *sgname, ilbd_cmd_t cmd) 38 { 39 ilb_status_t rc; 40 ilb_comm_t *ic; 41 size_t ic_sz; 42 43 if (h == ILB_INVALID_HANDLE || sgname == NULL || *sgname == '\0') 44 return (ILB_STATUS_EINVAL); 45 46 if (strlen(sgname) > ILB_SGNAME_SZ - 1) 47 return (ILB_STATUS_NAMETOOLONG); 48 49 if ((ic = i_ilb_alloc_req(cmd, &ic_sz)) == NULL) 50 return (ILB_STATUS_ENOMEM); 51 52 (void) strlcpy((char *)&ic->ic_data, sgname, sizeof (ilbd_name_t)); 53 54 rc = i_ilb_do_comm(h, ic, ic_sz, ic, &ic_sz); 55 if (rc != ILB_STATUS_OK) 56 goto out; 57 58 if (ic->ic_cmd != ILBD_CMD_OK) 59 rc = *(ilb_status_t *)&ic->ic_data; 60 out: 61 free(ic); 62 return (rc); 63 } 64 65 ilb_status_t 66 ilb_destroy_servergroup(ilb_handle_t h, const char *sgname) 67 { 68 return (i_ilb_addrem_sg(h, sgname, ILBD_DESTROY_SERVERGROUP)); 69 } 70 71 ilb_status_t 72 ilb_create_servergroup(ilb_handle_t h, const char *sgname) 73 { 74 return (i_ilb_addrem_sg(h, sgname, ILBD_CREATE_SERVERGROUP)); 75 } 76 77 static ilb_status_t 78 i_ilb_addrem_server_to_group(ilb_handle_t h, const char *sgname, 79 ilb_server_data_t *srv, ilbd_cmd_t cmd) 80 { 81 ilb_status_t rc = ILB_STATUS_OK; 82 ilb_sg_info_t *sg; 83 ilb_sg_srv_t *sgs; 84 in_port_t h_maxport, h_minport; 85 ilb_comm_t *ic; 86 size_t ic_sz; 87 88 if (h == ILB_INVALID_HANDLE || sgname == NULL || 89 *sgname == '\0' || srv == NULL) 90 return (ILB_STATUS_EINVAL); 91 92 if (strlen(sgname) > ILB_SGNAME_SZ - 1) 93 return (ILB_STATUS_NAMETOOLONG); 94 95 /* now all the checks have passed, we can pass on the goods */ 96 if ((ic = i_ilb_alloc_req(cmd, &ic_sz)) == NULL) 97 return (ILB_STATUS_ENOMEM); 98 99 sg = (ilb_sg_info_t *)&ic->ic_data; 100 sg->sg_srvcount = 1; 101 (void) strlcpy(sg->sg_name, sgname, sizeof (sg->sg_name)); 102 103 sgs = &sg->sg_servers[0]; 104 105 IP_COPY_CLI_2_IMPL(&srv->sd_addr, &sgs->sgs_addr); 106 h_minport = ntohs(srv->sd_minport); 107 h_maxport = ntohs(srv->sd_maxport); 108 sgs->sgs_minport = srv->sd_minport; 109 if (h_minport != 0 && h_maxport < h_minport) 110 sgs->sgs_maxport = srv->sd_minport; 111 else 112 sgs->sgs_maxport = srv->sd_maxport; 113 114 sgs->sgs_flags = srv->sd_flags; 115 if (srv->sd_srvID[0] == ILB_SRVID_PREFIX) 116 (void) strlcpy(sgs->sgs_srvID, srv->sd_srvID, 117 sizeof (sgs->sgs_srvID)); 118 119 rc = i_ilb_do_comm(h, ic, ic_sz, ic, &ic_sz); 120 if (rc != ILB_STATUS_OK) 121 goto out; 122 123 if (ic->ic_cmd != ILBD_CMD_OK) 124 rc = *(ilb_status_t *)&ic->ic_data; 125 126 out: 127 free(ic); 128 return (rc); 129 } 130 131 ilb_status_t 132 ilb_add_server_to_group(ilb_handle_t h, const char *sgname, 133 ilb_server_data_t *srv) 134 { 135 return (i_ilb_addrem_server_to_group(h, sgname, srv, 136 ILBD_ADD_SERVER_TO_GROUP)); 137 } 138 139 ilb_status_t 140 ilb_rem_server_from_group(ilb_handle_t h, const char *sgname, 141 ilb_server_data_t *srv) 142 { 143 return (i_ilb_addrem_server_to_group(h, sgname, srv, 144 ILBD_REM_SERVER_FROM_GROUP)); 145 } 146 147 static ilb_status_t 148 i_ilb_retrieve_sg_names(ilb_handle_t h, ilb_comm_t **rbuf, size_t *rbufsz) 149 { 150 ilb_status_t rc; 151 ilb_comm_t ic, *tmp_rbuf; 152 153 *rbufsz = ILBD_MSG_SIZE; 154 if ((tmp_rbuf = malloc(*rbufsz)) == NULL) 155 return (ILB_STATUS_ENOMEM); 156 157 ic.ic_cmd = ILBD_RETRIEVE_SG_NAMES; 158 rc = i_ilb_do_comm(h, &ic, sizeof (ic), tmp_rbuf, rbufsz); 159 if (rc != ILB_STATUS_OK) 160 goto out; 161 162 if (tmp_rbuf->ic_cmd == ILBD_CMD_OK) { 163 *rbuf = tmp_rbuf; 164 return (rc); 165 } 166 rc = *(ilb_status_t *)&tmp_rbuf->ic_data; 167 out: 168 free(tmp_rbuf); 169 *rbuf = NULL; 170 return (rc); 171 } 172 173 static ilb_status_t 174 i_ilb_retrieve_sg_hosts(ilb_handle_t h, const char *sgname, ilb_comm_t **rbuf, 175 size_t *rbufsz) 176 { 177 ilb_status_t rc; 178 ilb_comm_t *ic, *tmp_rbuf; 179 size_t ic_sz; 180 181 if ((ic = i_ilb_alloc_req(ILBD_RETRIEVE_SG_HOSTS, &ic_sz)) == NULL) 182 return (ILB_STATUS_ENOMEM); 183 *rbufsz = ILBD_MSG_SIZE; 184 if ((tmp_rbuf = malloc(*rbufsz)) == NULL) { 185 free(ic); 186 *rbuf = NULL; 187 return (ILB_STATUS_ENOMEM); 188 } 189 190 (void) strlcpy((char *)&ic->ic_data, sgname, sizeof (ilbd_name_t)); 191 rc = i_ilb_do_comm(h, ic, ic_sz, tmp_rbuf, rbufsz); 192 if (rc != ILB_STATUS_OK) 193 goto out; 194 195 if (tmp_rbuf->ic_cmd == ILBD_CMD_OK) { 196 *rbuf = tmp_rbuf; 197 free(ic); 198 return (rc); 199 } 200 rc = *(ilb_status_t *)&tmp_rbuf->ic_data; 201 out: 202 free(ic); 203 free(tmp_rbuf); 204 *rbuf = NULL; 205 return (rc); 206 } 207 208 typedef enum { 209 walk_servers, 210 walk_sg 211 } sgwalk_t; 212 213 /* 214 * "walks" one sg (retrieves data) and depending on "walktype" argument 215 * call servergroup function once per sg or server function once 216 * for every server. in both cases, the argument "f" is cast to 217 * be the proper function pointer type 218 */ 219 static ilb_status_t 220 i_ilb_walk_one_sg(ilb_handle_t h, void *f, const char *sgname, void *arg, 221 sgwalk_t walktype) 222 { 223 ilb_status_t rc = ILB_STATUS_OK; 224 ilb_sg_info_t *sg_info; 225 ilb_sg_srv_t *srv; 226 int i; 227 ilb_comm_t *rbuf; 228 size_t rbufsz; 229 230 rc = i_ilb_retrieve_sg_hosts(h, sgname, &rbuf, &rbufsz); 231 if (rc != ILB_STATUS_OK) 232 return (rc); 233 sg_info = (ilb_sg_info_t *)&rbuf->ic_data; 234 235 if (walktype == walk_sg) { 236 sg_walkerfunc_t sg_func = (sg_walkerfunc_t)f; 237 ilb_sg_data_t sgd; 238 239 (void) strlcpy(sgd.sgd_name, sg_info->sg_name, 240 sizeof (sgd.sgd_name)); 241 sgd.sgd_srvcount = sg_info->sg_srvcount; 242 sgd.sgd_flags = sg_info->sg_flags; 243 rc = sg_func(h, &sgd, arg); 244 goto out; 245 } 246 247 for (i = 0; i < sg_info->sg_srvcount; i++) { 248 srv_walkerfunc_t srv_func = (srv_walkerfunc_t)f; 249 ilb_server_data_t sd; 250 251 srv = &sg_info->sg_servers[i]; 252 IP_COPY_IMPL_2_CLI(&srv->sgs_addr, &sd.sd_addr); 253 sd.sd_minport = srv->sgs_minport; 254 sd.sd_maxport = srv->sgs_maxport; 255 sd.sd_flags = srv->sgs_flags; 256 (void) strlcpy(sd.sd_srvID, srv->sgs_srvID, 257 sizeof (sd.sd_srvID)); 258 259 rc = srv_func(h, &sd, sg_info->sg_name, arg); 260 if (rc != ILB_STATUS_OK) 261 break; 262 } 263 264 out: 265 free(rbuf); 266 return (rc); 267 } 268 269 /* 270 * wrapper function for i_walk_one_sg; if necessary, gets list of 271 * SG names and calles i_walk_one_sg with every name 272 */ 273 static ilb_status_t 274 i_walk_sgs(ilb_handle_t h, void *f, const char *sgname, 275 void *arg, sgwalk_t walktype) 276 { 277 ilb_status_t rc; 278 ilbd_namelist_t *sgl; 279 ilb_comm_t *rbuf; 280 size_t rbufsz; 281 int i; 282 283 if (sgname != NULL) { 284 rc = i_ilb_walk_one_sg(h, f, sgname, arg, walktype); 285 return (rc); 286 } 287 288 rc = i_ilb_retrieve_sg_names(h, &rbuf, &rbufsz); 289 if (rc != ILB_STATUS_OK) 290 return (rc); 291 sgl = (ilbd_namelist_t *)&rbuf->ic_data; 292 293 for (i = 0; i < sgl->ilbl_count; i++) { 294 rc = i_ilb_walk_one_sg(h, f, sgl->ilbl_name[i], arg, walktype); 295 /* 296 * The server group may have been removed by another 297 * process, just continue. 298 */ 299 if (rc == ILB_STATUS_SGUNAVAIL) { 300 rc = ILB_STATUS_OK; 301 continue; 302 } 303 if (rc != ILB_STATUS_OK) 304 break; 305 } 306 free(rbuf); 307 return (rc); 308 } 309 310 ilb_status_t 311 ilb_walk_servergroups(ilb_handle_t h, sg_walkerfunc_t f, const char *sgname, 312 void *arg) 313 { 314 return (i_walk_sgs(h, (void *)f, sgname, arg, walk_sg)); 315 } 316 317 ilb_status_t 318 ilb_walk_servers(ilb_handle_t h, srv_walkerfunc_t f, const char *sgname, 319 void *arg) 320 { 321 return (i_walk_sgs(h, (void *)f, sgname, arg, walk_servers)); 322 } 323 324 static ilb_status_t 325 ilb_Xable_server(ilb_handle_t h, ilb_server_data_t *srv, void *reserved, 326 ilbd_cmd_t cmd) 327 { 328 ilb_status_t rc; 329 ilb_sg_info_t *sg_info; 330 ilb_sg_srv_t *sgs; 331 in_port_t h_maxport, h_minport; 332 ilb_comm_t *ic; 333 size_t ic_sz; 334 335 if (h == NULL) 336 return (ILB_STATUS_EINVAL); 337 338 /* 339 * In this implementation, this needs to be NULL, so 340 * there's no ugly surprises with old apps once we attach 341 * meaning to this parameter. 342 */ 343 if (reserved != NULL) 344 return (ILB_STATUS_EINVAL); 345 346 /* now all the checks have passed, we can pass on the goods */ 347 if ((ic = i_ilb_alloc_req(cmd, &ic_sz)) == NULL) 348 return (ILB_STATUS_ENOMEM); 349 350 sg_info = (ilb_sg_info_t *)&ic->ic_data; 351 sg_info->sg_srvcount = 1; 352 353 sgs = &sg_info->sg_servers[0]; 354 355 /* make sure min_port <= max_port; comparison in host byte order! */ 356 h_maxport = ntohs(srv->sd_maxport); 357 h_minport = ntohs(srv->sd_minport); 358 if (h_maxport != 0 && h_maxport < h_minport) 359 sgs->sgs_maxport = sgs->sgs_minport; 360 else 361 sgs->sgs_maxport = srv->sd_maxport; 362 sgs->sgs_minport = srv->sd_minport; 363 364 sgs->sgs_flags = srv->sd_flags; 365 (void) strlcpy(sgs->sgs_srvID, srv->sd_srvID, sizeof (sgs->sgs_srvID)); 366 IP_COPY_CLI_2_IMPL(&srv->sd_addr, &sgs->sgs_addr); 367 368 rc = i_ilb_do_comm(h, ic, ic_sz, ic, &ic_sz); 369 if (rc != ILB_STATUS_OK) 370 goto out; 371 372 if (ic->ic_cmd != ILBD_CMD_OK) 373 rc = *(ilb_status_t *)&ic->ic_data; 374 out: 375 free(ic); 376 return (rc); 377 } 378 379 ilb_status_t 380 ilb_enable_server(ilb_handle_t h, ilb_server_data_t *srv, void *reserved) 381 { 382 return (ilb_Xable_server(h, srv, reserved, ILBD_ENABLE_SERVER)); 383 } 384 385 ilb_status_t 386 ilb_disable_server(ilb_handle_t h, ilb_server_data_t *srv, void *reserved) 387 { 388 return (ilb_Xable_server(h, srv, reserved, ILBD_DISABLE_SERVER)); 389 } 390 391 static ilb_status_t 392 i_ilb_fillin_srvdata(ilb_handle_t h, ilb_server_data_t *srv, const char *sgname, 393 ilbd_cmd_t cmd) 394 { 395 ilb_status_t rc; 396 ilb_sg_info_t *sg_info; 397 ilb_sg_srv_t *sgs; 398 ilb_comm_t *ic; 399 size_t ic_sz; 400 ilb_comm_t *rbuf; 401 size_t rbufsz; 402 403 if (h == ILB_INVALID_HANDLE || sgname == NULL || 404 *sgname == '\0' || srv == NULL) 405 return (ILB_STATUS_EINVAL); 406 407 if (cmd == ILBD_SRV_ID2ADDR && srv->sd_srvID[0] == '\0') 408 return (ILB_STATUS_EINVAL); 409 if (cmd == ILBD_SRV_ADDR2ID && !IS_AF_VALID(srv->sd_addr.ia_af)) 410 return (ILB_STATUS_EINVAL); 411 412 if ((ic = i_ilb_alloc_req(cmd, &ic_sz)) == NULL) 413 return (ILB_STATUS_ENOMEM); 414 rbufsz = sizeof (ilb_comm_t) + sizeof (ilb_sg_srv_t); 415 if ((rbuf = malloc(rbufsz)) == NULL) { 416 free(ic); 417 return (ILB_STATUS_ENOMEM); 418 } 419 420 sg_info = (ilb_sg_info_t *)&ic->ic_data; 421 sg_info->sg_srvcount = 1; 422 (void) strlcpy(sg_info->sg_name, sgname, sizeof (sg_info->sg_name)); 423 424 sgs = &sg_info->sg_servers[0]; 425 426 if (cmd == ILBD_SRV_ID2ADDR) 427 (void) strlcpy(sgs->sgs_srvID, srv->sd_srvID, 428 sizeof (sgs->sgs_srvID)); 429 else 430 IP_COPY_CLI_2_IMPL(&srv->sd_addr, &sgs->sgs_addr); 431 432 rc = i_ilb_do_comm(h, ic, ic_sz, rbuf, &rbufsz); 433 if (rc != ILB_STATUS_OK) 434 goto out; 435 436 if (rbuf->ic_cmd == ILBD_CMD_OK) { 437 sgs = (ilb_sg_srv_t *)&rbuf->ic_data; 438 if (cmd == ILBD_SRV_ID2ADDR) { 439 IP_COPY_IMPL_2_CLI(&sgs->sgs_addr, &srv->sd_addr); 440 } else { 441 (void) strlcpy(srv->sd_srvID, sgs->sgs_srvID, 442 sizeof (sgs->sgs_srvID)); 443 } 444 return (rc); 445 } 446 447 rc = *(ilb_status_t *)&rbuf->ic_data; 448 out: 449 free(ic); 450 return (rc); 451 } 452 453 ilb_status_t 454 ilb_srvID_to_address(ilb_handle_t h, ilb_server_data_t *srv, const char *sgname) 455 { 456 return (i_ilb_fillin_srvdata(h, srv, sgname, ILBD_SRV_ID2ADDR)); 457 458 } 459 460 ilb_status_t 461 ilb_address_to_srvID(ilb_handle_t h, ilb_server_data_t *srv, const char *sgname) 462 { 463 return (i_ilb_fillin_srvdata(h, srv, sgname, ILBD_SRV_ADDR2ID)); 464 } 465