xref: /titanic_44/usr/src/lib/libilb/common/ilb_sg.c (revision 4d0e50075058332ce0cd62bc2669a8a4dea45da0)
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