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 
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/stropts.h>
33 #include <netinet/in.h>
34 #include <stddef.h>
35 #include "libilb.h"
36 #include "libilb_impl.h"
37 
38 /* ARGSUSED */
39 static ilb_status_t
i_drop_hc(ilb_handle_t h,ilb_hc_info_t * hc,void * arg)40 i_drop_hc(ilb_handle_t h, ilb_hc_info_t *hc, void *arg)
41 {
42 	return (ilb_destroy_hc(h, hc->hci_name));
43 }
44 
45 /* ARGSUSED */
46 static ilb_status_t
i_drop_rule(ilb_handle_t h,ilb_rule_data_t * rd,void * arg)47 i_drop_rule(ilb_handle_t h, ilb_rule_data_t *rd, void *arg)
48 {
49 	return (ilb_destroy_rule(h, rd->r_name));
50 }
51 
52 /* ARGSUSED */
53 static ilb_status_t
i_drop_sg_srvs(ilb_handle_t h,ilb_server_data_t * srv,const char * sgname,void * arg)54 i_drop_sg_srvs(ilb_handle_t h, ilb_server_data_t *srv, const char *sgname,
55     void *arg)
56 {
57 	return (ilb_rem_server_from_group(h, sgname, srv));
58 }
59 
60 /* ARGSUSED */
61 static ilb_status_t
i_drop_sg(ilb_handle_t h,ilb_sg_data_t * sg,void * arg)62 i_drop_sg(ilb_handle_t h, ilb_sg_data_t *sg, void *arg)
63 {
64 	ilb_status_t	rc;
65 
66 	rc = ilb_walk_servers(h, i_drop_sg_srvs, sg->sgd_name, (void *)sg);
67 	if (rc != ILB_STATUS_OK)
68 		return (rc);
69 
70 	return (ilb_destroy_servergroup(h, sg->sgd_name));
71 }
72 
73 ilb_status_t
ilb_reset_config(ilb_handle_t h)74 ilb_reset_config(ilb_handle_t h)
75 {
76 	ilb_status_t	rc;
77 
78 	if (h == NULL)
79 		return (ILB_STATUS_EINVAL);
80 
81 	rc = ilb_walk_rules(h, i_drop_rule, NULL, NULL);
82 	if (rc != ILB_STATUS_OK)
83 		goto out;
84 
85 	rc = ilb_walk_servergroups(h, i_drop_sg, NULL, NULL);
86 	if (rc != ILB_STATUS_OK)
87 		goto out;
88 
89 	rc = ilb_walk_hc(h, i_drop_hc, NULL);
90 out:
91 	return (rc);
92 }
93 
94 ilb_status_t
ilb_create_rule(ilb_handle_t h,const ilb_rule_data_t * rd)95 ilb_create_rule(ilb_handle_t h, const ilb_rule_data_t *rd)
96 {
97 	ilb_status_t	rc;
98 	ilb_comm_t	*ic;
99 	size_t		ic_sz;
100 	ilb_rule_info_t	*rl;
101 
102 	if (h == ILB_INVALID_HANDLE || rd == NULL || *rd->r_name == '\0')
103 		return (ILB_STATUS_EINVAL);
104 
105 	if ((ic = i_ilb_alloc_req(ILBD_CREATE_RULE, &ic_sz)) == NULL)
106 		return (ILB_STATUS_ENOMEM);
107 	rl = (ilb_rule_info_t *)&ic->ic_data;
108 
109 	/*
110 	 * Since the IP address representation in ilb_rule_data_t and
111 	 * ilb_rule_info_t is different, we need to convert between
112 	 * them.
113 	 */
114 	(void) strlcpy(rl->rl_name, rd->r_name, sizeof (rl->rl_name));
115 	(void) strlcpy(rl->rl_sgname, rd->r_sgname, sizeof (rl->rl_sgname));
116 	(void) strlcpy(rl->rl_hcname, rd->r_hcname, sizeof (rl->rl_hcname));
117 	rl->rl_flags = rd->r_flags;
118 	rl->rl_proto = rd->r_proto;
119 	rl->rl_ipversion = rd->r_vip.ia_af;
120 	rl->rl_minport = rd->r_minport;
121 	if (ntohs(rd->r_maxport) < ntohs(rd->r_minport))
122 		rl->rl_maxport = rd->r_minport;
123 	else
124 		rl->rl_maxport = rd->r_maxport;
125 	rl->rl_algo = rd->r_algo;
126 	rl->rl_topo = rd->r_topo;
127 	rl->rl_conndrain = rd->r_conndrain;
128 	rl->rl_nat_timeout = rd->r_nat_timeout;
129 	rl->rl_sticky_timeout = rd->r_sticky_timeout;
130 	rl->rl_hcport = rd->r_hcport;
131 	rl->rl_hcpflag = rd->r_hcpflag;
132 
133 	IP_COPY_CLI_2_IMPL(&rd->r_vip, &rl->rl_vip);
134 	IP_COPY_CLI_2_IMPL(&rd->r_stickymask, &rl->rl_stickymask);
135 	IP_COPY_CLI_2_IMPL(&rd->r_nat_src_start, &rl->rl_nat_src_start);
136 	IP_COPY_CLI_2_IMPL(&rd->r_nat_src_end, &rl->rl_nat_src_end);
137 
138 	rc = i_ilb_do_comm(h, ic, ic_sz, ic, &ic_sz);
139 	if (rc != ILB_STATUS_OK)
140 		goto out;
141 
142 	if (ic->ic_cmd != ILBD_CMD_OK)
143 		rc = *(ilb_status_t *)&ic->ic_data;
144 
145 out:
146 	free(ic);
147 	return (rc);
148 }
149 
150 static ilb_status_t
i_ilb_rule_action(ilb_handle_t h,const char * name,ilbd_cmd_t cmd)151 i_ilb_rule_action(ilb_handle_t h, const char *name, ilbd_cmd_t cmd)
152 {
153 	ilb_status_t	rc;
154 	ilb_comm_t	*ic;
155 	size_t		ic_sz;
156 
157 	if (h == ILB_INVALID_HANDLE)
158 		return (ILB_STATUS_EINVAL);
159 
160 	if ((ic = i_ilb_alloc_req(cmd, &ic_sz)) == NULL)
161 		return (ILB_STATUS_ENOMEM);
162 
163 	if (name == NULL) {
164 		bzero(&ic->ic_data, sizeof (ilbd_name_t));
165 	} else {
166 		(void) strlcpy((char *)&ic->ic_data, name,
167 		    sizeof (ilbd_name_t));
168 	}
169 
170 	rc = i_ilb_do_comm(h, ic, ic_sz, ic, &ic_sz);
171 	if (rc != ILB_STATUS_OK)
172 		goto out;
173 
174 	if (ic->ic_cmd != ILBD_CMD_OK)
175 		rc = *(ilb_status_t *)&ic->ic_data;
176 
177 out:
178 	free(ic);
179 	return (rc);
180 }
181 
182 ilb_status_t
ilb_destroy_rule(ilb_handle_t h,const char * name)183 ilb_destroy_rule(ilb_handle_t h, const char *name)
184 {
185 	return (i_ilb_rule_action(h, name, ILBD_DESTROY_RULE));
186 }
187 
188 ilb_status_t
ilb_enable_rule(ilb_handle_t h,const char * name)189 ilb_enable_rule(ilb_handle_t h, const char *name)
190 {
191 	return (i_ilb_rule_action(h, name, ILBD_ENABLE_RULE));
192 }
193 
194 ilb_status_t
ilb_disable_rule(ilb_handle_t h,const char * name)195 ilb_disable_rule(ilb_handle_t h, const char *name)
196 {
197 	return (i_ilb_rule_action(h, name, ILBD_DISABLE_RULE));
198 }
199 
200 ilb_status_t
i_ilb_retrieve_rule_names(ilb_handle_t h,ilb_comm_t ** rbuf,size_t * rbufsz)201 i_ilb_retrieve_rule_names(ilb_handle_t h, ilb_comm_t **rbuf, size_t *rbufsz)
202 {
203 	ilb_status_t	rc;
204 	ilb_comm_t	ic, *tmp_rbuf;
205 
206 	*rbufsz = ILBD_MSG_SIZE;
207 	if ((tmp_rbuf = malloc(*rbufsz)) == NULL)
208 		return (ILB_STATUS_ENOMEM);
209 
210 	ic.ic_cmd = ILBD_RETRIEVE_RULE_NAMES;
211 
212 	rc = i_ilb_do_comm(h, &ic, sizeof (ic), tmp_rbuf, rbufsz);
213 	if (rc != ILB_STATUS_OK)
214 		goto out;
215 
216 	if (tmp_rbuf->ic_cmd == ILBD_CMD_OK) {
217 		*rbuf = tmp_rbuf;
218 		return (rc);
219 	}
220 	rc = *(ilb_status_t *)&tmp_rbuf->ic_data;
221 out:
222 	free(tmp_rbuf);
223 	*rbuf = NULL;
224 	return (rc);
225 }
226 
227 static ilb_status_t
i_ilb_walk_one_rule(ilb_handle_t h,rule_walkerfunc_t f,const char * name,void * arg)228 i_ilb_walk_one_rule(ilb_handle_t h, rule_walkerfunc_t f, const char *name,
229     void *arg)
230 {
231 	ilb_status_t		rc = ILB_STATUS_OK;
232 	ilb_rule_info_t		*rl = NULL;
233 	ilb_rule_data_t		rd;
234 	ilb_comm_t		*ic, *rbuf;
235 	size_t			ic_sz, rbufsz;
236 
237 
238 	if ((ic = i_ilb_alloc_req(ILBD_RETRIEVE_RULE, &ic_sz)) == NULL)
239 		return (ILB_STATUS_ENOMEM);
240 	rbufsz = sizeof (ilb_comm_t) + sizeof (ilb_rule_info_t);
241 	if ((rbuf = malloc(rbufsz)) == NULL) {
242 		free(ic);
243 		return (ILB_STATUS_ENOMEM);
244 	}
245 
246 	(void) strlcpy((char *)&ic->ic_data,  name, sizeof (ilbd_name_t));
247 	rc = i_ilb_do_comm(h, ic, ic_sz, rbuf, &rbufsz);
248 	if (rc != ILB_STATUS_OK)
249 		goto out;
250 	if (rbuf->ic_cmd != ILBD_CMD_OK) {
251 		rc = *(ilb_status_t *)&rbuf->ic_data;
252 		goto out;
253 	}
254 	rl = (ilb_rule_info_t *)&rbuf->ic_data;
255 
256 	/*
257 	 * Since the IP address representation in ilb_rule_data_t and
258 	 * ilb_rule_info_t is different, we need to convert between
259 	 * them.
260 	 */
261 	(void) strlcpy(rd.r_name, rl->rl_name, sizeof (rd.r_name));
262 	(void) strlcpy(rd.r_hcname, rl->rl_hcname, sizeof (rd.r_hcname));
263 	(void) strlcpy(rd.r_sgname, rl->rl_sgname, sizeof (rd.r_sgname));
264 	rd.r_flags = rl->rl_flags;
265 	rd.r_proto = rl->rl_proto;
266 	rd.r_minport = rl->rl_minport;
267 	rd.r_maxport = rl->rl_maxport;
268 	rd.r_algo = rl->rl_algo;
269 	rd.r_topo = rl->rl_topo;
270 	rd.r_conndrain = rl->rl_conndrain;
271 	rd.r_nat_timeout = rl->rl_nat_timeout;
272 	rd.r_sticky_timeout = rl->rl_sticky_timeout;
273 	rd.r_hcport = rl->rl_hcport;
274 	rd.r_hcpflag = rl->rl_hcpflag;
275 
276 	IP_COPY_IMPL_2_CLI(&rl->rl_vip, &rd.r_vip);
277 	IP_COPY_IMPL_2_CLI(&rl->rl_nat_src_start, &rd.r_nat_src_start);
278 	IP_COPY_IMPL_2_CLI(&rl->rl_nat_src_end, &rd.r_nat_src_end);
279 	IP_COPY_IMPL_2_CLI(&rl->rl_stickymask, &rd.r_stickymask);
280 
281 	rc = f(h, &rd, arg);
282 
283 out:
284 	free(ic);
285 	free(rbuf);
286 	return (rc);
287 }
288 
289 ilb_status_t
ilb_walk_rules(ilb_handle_t h,rule_walkerfunc_t f,const char * name,void * arg)290 ilb_walk_rules(ilb_handle_t h, rule_walkerfunc_t f, const char *name,
291     void *arg)
292 {
293 	ilb_status_t	rc;
294 	ilbd_namelist_t	*names;
295 	ilb_comm_t	*rbuf;
296 	size_t		rbufsz;
297 	int		i;
298 
299 	if (h == NULL)
300 		return (ILB_STATUS_EINVAL);
301 
302 	if (name != NULL)
303 		return (i_ilb_walk_one_rule(h, f, name, arg));
304 
305 	rc = i_ilb_retrieve_rule_names(h, &rbuf, &rbufsz);
306 	if (rc != ILB_STATUS_OK)
307 		return (rc);
308 
309 	names = (ilbd_namelist_t *)&rbuf->ic_data;
310 	for (i = 0; i < names->ilbl_count; i++) {
311 		rc = i_ilb_walk_one_rule(h, f, names->ilbl_name[i], arg);
312 		/*
313 		 * The rule may have been removed by another process since
314 		 * we retrieve all the rule names, just continue.
315 		 */
316 		if (rc == ILB_STATUS_ENOENT) {
317 			rc = ILB_STATUS_OK;
318 			continue;
319 		}
320 		if (rc != ILB_STATUS_OK)
321 			break;
322 	}
323 
324 	free(rbuf);
325 	return (rc);
326 }
327