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 */
39static ilb_status_t
40i_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 */
46static ilb_status_t
47i_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 */
53static ilb_status_t
54i_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 */
61static ilb_status_t
62i_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
73ilb_status_t
74ilb_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);
90out:
91	return (rc);
92}
93
94ilb_status_t
95ilb_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
145out:
146	free(ic);
147	return (rc);
148}
149
150static ilb_status_t
151i_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
177out:
178	free(ic);
179	return (rc);
180}
181
182ilb_status_t
183ilb_destroy_rule(ilb_handle_t h, const char *name)
184{
185	return (i_ilb_rule_action(h, name, ILBD_DESTROY_RULE));
186}
187
188ilb_status_t
189ilb_enable_rule(ilb_handle_t h, const char *name)
190{
191	return (i_ilb_rule_action(h, name, ILBD_ENABLE_RULE));
192}
193
194ilb_status_t
195ilb_disable_rule(ilb_handle_t h, const char *name)
196{
197	return (i_ilb_rule_action(h, name, ILBD_DISABLE_RULE));
198}
199
200ilb_status_t
201i_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;
221out:
222	free(tmp_rbuf);
223	*rbuf = NULL;
224	return (rc);
225}
226
227static ilb_status_t
228i_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
283out:
284	free(ic);
285	free(rbuf);
286	return (rc);
287}
288
289ilb_status_t
290ilb_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