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
i_ilb_addrem_sg(ilb_handle_t h,const char * sgname,ilbd_cmd_t cmd)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
ilb_destroy_servergroup(ilb_handle_t h,const char * sgname)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
ilb_create_servergroup(ilb_handle_t h,const char * sgname)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
i_ilb_addrem_server_to_group(ilb_handle_t h,const char * sgname,ilb_server_data_t * srv,ilbd_cmd_t cmd)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
ilb_add_server_to_group(ilb_handle_t h,const char * sgname,ilb_server_data_t * srv)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
ilb_rem_server_from_group(ilb_handle_t h,const char * sgname,ilb_server_data_t * srv)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
i_ilb_retrieve_sg_names(ilb_handle_t h,ilb_comm_t ** rbuf,size_t * rbufsz)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
i_ilb_retrieve_sg_hosts(ilb_handle_t h,const char * sgname,ilb_comm_t ** rbuf,size_t * rbufsz)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
i_ilb_walk_one_sg(ilb_handle_t h,void * f,const char * sgname,void * arg,sgwalk_t walktype)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
i_walk_sgs(ilb_handle_t h,void * f,const char * sgname,void * arg,sgwalk_t walktype)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
ilb_walk_servergroups(ilb_handle_t h,sg_walkerfunc_t f,const char * sgname,void * arg)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
ilb_walk_servers(ilb_handle_t h,srv_walkerfunc_t f,const char * sgname,void * arg)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
ilb_Xable_server(ilb_handle_t h,ilb_server_data_t * srv,void * reserved,ilbd_cmd_t cmd)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
ilb_enable_server(ilb_handle_t h,ilb_server_data_t * srv,void * reserved)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
ilb_disable_server(ilb_handle_t h,ilb_server_data_t * srv,void * reserved)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
i_ilb_fillin_srvdata(ilb_handle_t h,ilb_server_data_t * srv,const char * sgname,ilbd_cmd_t cmd)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
ilb_srvID_to_address(ilb_handle_t h,ilb_server_data_t * srv,const char * sgname)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
ilb_address_to_srvID(ilb_handle_t h,ilb_server_data_t * srv,const char * sgname)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