1dbed73cbSSangeeta Misra /*
2dbed73cbSSangeeta Misra  * CDDL HEADER START
3dbed73cbSSangeeta Misra  *
4dbed73cbSSangeeta Misra  * The contents of this file are subject to the terms of the
5dbed73cbSSangeeta Misra  * Common Development and Distribution License (the "License").
6dbed73cbSSangeeta Misra  * You may not use this file except in compliance with the License.
7dbed73cbSSangeeta Misra  *
8dbed73cbSSangeeta Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dbed73cbSSangeeta Misra  * or http://www.opensolaris.org/os/licensing.
10dbed73cbSSangeeta Misra  * See the License for the specific language governing permissions
11dbed73cbSSangeeta Misra  * and limitations under the License.
12dbed73cbSSangeeta Misra  *
13dbed73cbSSangeeta Misra  * When distributing Covered Code, include this CDDL HEADER in each
14dbed73cbSSangeeta Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dbed73cbSSangeeta Misra  * If applicable, add the following below this CDDL HEADER, with the
16dbed73cbSSangeeta Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17dbed73cbSSangeeta Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18dbed73cbSSangeeta Misra  *
19dbed73cbSSangeeta Misra  * CDDL HEADER END
20dbed73cbSSangeeta Misra  */
21dbed73cbSSangeeta Misra 
22dbed73cbSSangeeta Misra /*
233ae6a67dSSangeeta Misra  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24dbed73cbSSangeeta Misra  */
25dbed73cbSSangeeta Misra 
26dbed73cbSSangeeta Misra #include <stdlib.h>
27dbed73cbSSangeeta Misra #include <strings.h>
28dbed73cbSSangeeta Misra #include <stddef.h>
29dbed73cbSSangeeta Misra #include <unistd.h>
30dbed73cbSSangeeta Misra #include <sys/types.h>
31dbed73cbSSangeeta Misra #include <sys/socket.h>
32dbed73cbSSangeeta Misra #include <netinet/in.h>
33dbed73cbSSangeeta Misra #include <arpa/inet.h>
34dbed73cbSSangeeta Misra #include <sys/list.h>
35dbed73cbSSangeeta Misra #include <net/if.h>
36dbed73cbSSangeeta Misra #include <assert.h>
37dbed73cbSSangeeta Misra #include <errno.h>
38dbed73cbSSangeeta Misra #include <libintl.h>
39dbed73cbSSangeeta Misra #include <libilb.h>
40dbed73cbSSangeeta Misra #include <inet/ilb.h>
41dbed73cbSSangeeta Misra #include "libilb_impl.h"
42dbed73cbSSangeeta Misra #include "ilbd.h"
43dbed73cbSSangeeta Misra 
44dbed73cbSSangeeta Misra /* until we all use AF_* macros ... */
45dbed73cbSSangeeta Misra #define	AF_2_IPPROTO(_af)	(_af == AF_INET)?IPPROTO_IP:IPPROTO_IPV6
46dbed73cbSSangeeta Misra #define	IPPROTO_2_AF(_i)	(_i == IPPROTO_IP)?AF_INET:AF_INET6
47dbed73cbSSangeeta Misra 
483ae6a67dSSangeeta Misra #define	PROTOCOL_LEN	16				/* protocol type */
493ae6a67dSSangeeta Misra #define	ADDR_LEN	(2 * INET6_ADDRSTRLEN + 1)	/* prxy src range */
503ae6a67dSSangeeta Misra #define	PORT_LEN	6			/* hcport:1-65535 or "ANY" */
513ae6a67dSSangeeta Misra 
52dbed73cbSSangeeta Misra static ilb_status_t ilbd_disable_one_rule(ilbd_rule_t *, boolean_t);
53dbed73cbSSangeeta Misra static uint32_t i_flags_d2k(int);
54dbed73cbSSangeeta Misra 
55dbed73cbSSangeeta Misra #define	ILB_SGSRV_2_KSRV(s, k)			\
56dbed73cbSSangeeta Misra 	(k)->addr  = (s)->sgs_addr;		\
57dbed73cbSSangeeta Misra 	(k)->min_port = (s)->sgs_minport;	\
58dbed73cbSSangeeta Misra 	(k)->max_port = (s)->sgs_maxport;	\
59dbed73cbSSangeeta Misra 	(k)->flags = i_flags_d2k((s)->sgs_flags);	\
60dbed73cbSSangeeta Misra 	(k)->err = 0;				\
61dbed73cbSSangeeta Misra 	(void) strlcpy((k)->name, (s)->sgs_srvID, sizeof ((k)->name))
62dbed73cbSSangeeta Misra 
63dbed73cbSSangeeta Misra list_t		ilbd_rule_hlist;
64dbed73cbSSangeeta Misra 
65dbed73cbSSangeeta Misra static ilb_algo_t
algo_impl2lib(ilb_algo_impl_t a)66dbed73cbSSangeeta Misra algo_impl2lib(ilb_algo_impl_t a)
67dbed73cbSSangeeta Misra {
68dbed73cbSSangeeta Misra 	switch (a) {
69dbed73cbSSangeeta Misra 	case ILB_ALG_IMPL_ROUNDROBIN:
70dbed73cbSSangeeta Misra 		return (ILB_ALG_ROUNDROBIN);
71dbed73cbSSangeeta Misra 	case ILB_ALG_IMPL_HASH_IP:
72dbed73cbSSangeeta Misra 		return (ILB_ALG_HASH_IP);
73dbed73cbSSangeeta Misra 	case ILB_ALG_IMPL_HASH_IP_SPORT:
74dbed73cbSSangeeta Misra 		return (ILB_ALG_HASH_IP_SPORT);
75dbed73cbSSangeeta Misra 	case ILB_ALG_IMPL_HASH_IP_VIP:
76dbed73cbSSangeeta Misra 		return (ILB_ALG_HASH_IP_VIP);
77dbed73cbSSangeeta Misra 	}
78dbed73cbSSangeeta Misra 	return (0);
79dbed73cbSSangeeta Misra }
80dbed73cbSSangeeta Misra 
81dbed73cbSSangeeta Misra static ilb_topo_t
topo_impl2lib(ilb_topo_impl_t t)82dbed73cbSSangeeta Misra topo_impl2lib(ilb_topo_impl_t t)
83dbed73cbSSangeeta Misra {
84dbed73cbSSangeeta Misra 	switch (t) {
85dbed73cbSSangeeta Misra 	case ILB_TOPO_IMPL_DSR:
86dbed73cbSSangeeta Misra 		return (ILB_TOPO_DSR);
87dbed73cbSSangeeta Misra 	case ILB_TOPO_IMPL_NAT:
88dbed73cbSSangeeta Misra 		return (ILB_TOPO_NAT);
89dbed73cbSSangeeta Misra 	case ILB_TOPO_IMPL_HALF_NAT:
90dbed73cbSSangeeta Misra 		return (ILB_TOPO_HALF_NAT);
91dbed73cbSSangeeta Misra 	}
92dbed73cbSSangeeta Misra 	return (0);
93dbed73cbSSangeeta Misra }
94dbed73cbSSangeeta Misra 
95dbed73cbSSangeeta Misra ilb_algo_impl_t
algo_lib2impl(ilb_algo_t a)96dbed73cbSSangeeta Misra algo_lib2impl(ilb_algo_t a)
97dbed73cbSSangeeta Misra {
98dbed73cbSSangeeta Misra 	switch (a) {
99dbed73cbSSangeeta Misra 	case ILB_ALG_ROUNDROBIN:
100dbed73cbSSangeeta Misra 		return (ILB_ALG_IMPL_ROUNDROBIN);
101dbed73cbSSangeeta Misra 	case ILB_ALG_HASH_IP:
102dbed73cbSSangeeta Misra 		return (ILB_ALG_IMPL_HASH_IP);
103dbed73cbSSangeeta Misra 	case ILB_ALG_HASH_IP_SPORT:
104dbed73cbSSangeeta Misra 		return (ILB_ALG_IMPL_HASH_IP_SPORT);
105dbed73cbSSangeeta Misra 	case ILB_ALG_HASH_IP_VIP:
106dbed73cbSSangeeta Misra 		return (ILB_ALG_IMPL_HASH_IP_VIP);
107dbed73cbSSangeeta Misra 	}
108dbed73cbSSangeeta Misra 	return (0);
109dbed73cbSSangeeta Misra }
110dbed73cbSSangeeta Misra 
111dbed73cbSSangeeta Misra ilb_topo_impl_t
topo_lib2impl(ilb_topo_t t)112dbed73cbSSangeeta Misra topo_lib2impl(ilb_topo_t t)
113dbed73cbSSangeeta Misra {
114dbed73cbSSangeeta Misra 	switch (t) {
115dbed73cbSSangeeta Misra 	case ILB_TOPO_DSR:
116dbed73cbSSangeeta Misra 		return (ILB_TOPO_IMPL_DSR);
117dbed73cbSSangeeta Misra 	case ILB_TOPO_NAT:
118dbed73cbSSangeeta Misra 		return (ILB_TOPO_IMPL_NAT);
119dbed73cbSSangeeta Misra 	case ILB_TOPO_HALF_NAT:
120dbed73cbSSangeeta Misra 		return (ILB_TOPO_IMPL_HALF_NAT);
121dbed73cbSSangeeta Misra 	}
122dbed73cbSSangeeta Misra 	return (0);
123dbed73cbSSangeeta Misra }
124dbed73cbSSangeeta Misra 
125dbed73cbSSangeeta Misra /*
126dbed73cbSSangeeta Misra  * Walk the list of rules and check if its safe to add the
127dbed73cbSSangeeta Misra  * the server to the rule (this is a list of rules hanging
128dbed73cbSSangeeta Misra  * off of a server group)
129dbed73cbSSangeeta Misra  */
130dbed73cbSSangeeta Misra ilb_status_t
i_check_srv2rules(list_t * rlist,ilb_sg_srv_t * srv)131dbed73cbSSangeeta Misra i_check_srv2rules(list_t *rlist, ilb_sg_srv_t *srv)
132dbed73cbSSangeeta Misra {
133dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
134dbed73cbSSangeeta Misra 	ilbd_rule_t	*rl;
135dbed73cbSSangeeta Misra 	int		server_portrange, rule_portrange;
136dbed73cbSSangeeta Misra 	int		srv_minport, srv_maxport;
137dbed73cbSSangeeta Misra 	int		r_minport, r_maxport;
138dbed73cbSSangeeta Misra 
139dbed73cbSSangeeta Misra 	if (srv == NULL)
140dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
141dbed73cbSSangeeta Misra 
142dbed73cbSSangeeta Misra 	srv_minport = ntohs(srv->sgs_minport);
143dbed73cbSSangeeta Misra 	srv_maxport = ntohs(srv->sgs_maxport);
144dbed73cbSSangeeta Misra 
145dbed73cbSSangeeta Misra 	for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) {
146dbed73cbSSangeeta Misra 		r_minport = ntohs(rl->irl_minport);
147dbed73cbSSangeeta Misra 		r_maxport = ntohs(rl->irl_maxport);
148dbed73cbSSangeeta Misra 
149dbed73cbSSangeeta Misra 		if ((srv_minport != 0) && (srv_minport == srv_maxport)) {
150dbed73cbSSangeeta Misra 			/* server has single port */
151dbed73cbSSangeeta Misra 			if (rl->irl_topo == ILB_TOPO_DSR) {
152dbed73cbSSangeeta Misra 				/*
153dbed73cbSSangeeta Misra 				 * either we have a DSR rule with a port
154dbed73cbSSangeeta Misra 				 * range, or both server and rule
155dbed73cbSSangeeta Misra 				 * have single ports but their values
156dbed73cbSSangeeta Misra 				 * don't match - this is incompatible
157dbed73cbSSangeeta Misra 				 */
158dbed73cbSSangeeta Misra 				if (r_maxport > r_minport) {
159dbed73cbSSangeeta Misra 					rc = ILB_STATUS_INVAL_SRVR;
160dbed73cbSSangeeta Misra 					break;
161dbed73cbSSangeeta Misra 				} else if (srv_minport != r_minport) {
162dbed73cbSSangeeta Misra 					rc = ILB_STATUS_BADPORT;
163dbed73cbSSangeeta Misra 					break;
164dbed73cbSSangeeta Misra 				}
165dbed73cbSSangeeta Misra 			}
166dbed73cbSSangeeta Misra 			if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX &&
167dbed73cbSSangeeta Misra 			    rl->irl_hcport != srv_minport) {
168dbed73cbSSangeeta Misra 				rc = ILB_STATUS_BADPORT;
169dbed73cbSSangeeta Misra 				break;
170dbed73cbSSangeeta Misra 			}
171dbed73cbSSangeeta Misra 		} else if (srv_maxport > srv_minport) {
172dbed73cbSSangeeta Misra 			/* server has a port range */
173dbed73cbSSangeeta Misra 			if ((rl->irl_topo == ILB_TOPO_DSR) &&
174dbed73cbSSangeeta Misra 			    (r_maxport > r_minport)) {
175dbed73cbSSangeeta Misra 				if ((r_minport != srv_minport) ||
176dbed73cbSSangeeta Misra 				    (r_maxport != srv_maxport)) {
177dbed73cbSSangeeta Misra 					/*
178dbed73cbSSangeeta Misra 					 * we have a DSR rule with a port range
179dbed73cbSSangeeta Misra 					 * and its min and max port values
180dbed73cbSSangeeta Misra 					 * does not meet that of server's
181dbed73cbSSangeeta Misra 					 * - this is incompatible
182dbed73cbSSangeeta Misra 					 */
183dbed73cbSSangeeta Misra 					rc = ILB_STATUS_BADPORT;
184dbed73cbSSangeeta Misra 					break;
185dbed73cbSSangeeta Misra 				}
186dbed73cbSSangeeta Misra 			} else if ((rl->irl_topo == ILB_TOPO_DSR) &&
187dbed73cbSSangeeta Misra 			    (r_maxport == r_minport)) {
188dbed73cbSSangeeta Misra 					/*
189dbed73cbSSangeeta Misra 					 * we have a DSR rule with a single
190dbed73cbSSangeeta Misra 					 * port and a server with a port range
191dbed73cbSSangeeta Misra 					 * - this is incompatible
192dbed73cbSSangeeta Misra 					 */
193dbed73cbSSangeeta Misra 					rc = ILB_STATUS_INVAL_SRVR;
194dbed73cbSSangeeta Misra 					break;
195dbed73cbSSangeeta Misra 			} else if (((rl->irl_topo == ILB_TOPO_NAT) ||
196dbed73cbSSangeeta Misra 			    (rl->irl_topo == ILB_TOPO_HALF_NAT)) &&
197dbed73cbSSangeeta Misra 			    (r_maxport > r_minport)) {
198dbed73cbSSangeeta Misra 				server_portrange = srv_maxport - srv_minport;
199dbed73cbSSangeeta Misra 				rule_portrange = r_maxport - r_minport;
200dbed73cbSSangeeta Misra 				if (rule_portrange != server_portrange) {
201dbed73cbSSangeeta Misra 					/*
202dbed73cbSSangeeta Misra 					 * we have a NAT/Half-NAT rule with
203dbed73cbSSangeeta Misra 					 * a port range and server with a port
204dbed73cbSSangeeta Misra 					 * range and there is a mismatch in the
205dbed73cbSSangeeta Misra 					 * sizes of the port ranges - this is
206dbed73cbSSangeeta Misra 					 * incompatible
207dbed73cbSSangeeta Misra 					 */
208dbed73cbSSangeeta Misra 					rc = ILB_STATUS_INVAL_SRVR;
209dbed73cbSSangeeta Misra 					break;
210dbed73cbSSangeeta Misra 				}
211dbed73cbSSangeeta Misra 			}
212dbed73cbSSangeeta Misra 			if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX &&
213dbed73cbSSangeeta Misra 			    (rl->irl_hcport > srv_maxport ||
214dbed73cbSSangeeta Misra 			    rl->irl_hcport < srv_minport)) {
215dbed73cbSSangeeta Misra 				rc = ILB_STATUS_BADPORT;
216dbed73cbSSangeeta Misra 				break;
217dbed73cbSSangeeta Misra 			}
218dbed73cbSSangeeta Misra 		}
219dbed73cbSSangeeta Misra 	}
220dbed73cbSSangeeta Misra 
221dbed73cbSSangeeta Misra 	return (rc);
222dbed73cbSSangeeta Misra }
223dbed73cbSSangeeta Misra 
224dbed73cbSSangeeta Misra void
i_setup_rule_hlist(void)225dbed73cbSSangeeta Misra i_setup_rule_hlist(void)
226dbed73cbSSangeeta Misra {
227dbed73cbSSangeeta Misra 	list_create(&ilbd_rule_hlist, sizeof (ilbd_rule_t),
228dbed73cbSSangeeta Misra 	    offsetof(ilbd_rule_t, irl_link));
229dbed73cbSSangeeta Misra }
230dbed73cbSSangeeta Misra 
231dbed73cbSSangeeta Misra ilb_status_t
i_ilbd_save_rule(ilbd_rule_t * irl,ilbd_scf_cmd_t scf_cmd)232dbed73cbSSangeeta Misra i_ilbd_save_rule(ilbd_rule_t *irl, ilbd_scf_cmd_t scf_cmd)
233dbed73cbSSangeeta Misra {
234dbed73cbSSangeeta Misra 	boolean_t enable = irl->irl_flags & ILB_FLAGS_RULE_ENABLED;
235dbed73cbSSangeeta Misra 
236dbed73cbSSangeeta Misra 	switch (scf_cmd) {
237dbed73cbSSangeeta Misra 	case ILBD_SCF_CREATE:
238dbed73cbSSangeeta Misra 		return (ilbd_create_pg(ILBD_SCF_RULE, (void *)irl));
239dbed73cbSSangeeta Misra 	case ILBD_SCF_DESTROY:
240dbed73cbSSangeeta Misra 		return (ilbd_destroy_pg(ILBD_SCF_RULE, irl->irl_name));
241dbed73cbSSangeeta Misra 	case ILBD_SCF_ENABLE_DISABLE:
242dbed73cbSSangeeta Misra 		return (ilbd_change_prop(ILBD_SCF_RULE, irl->irl_name,
243dbed73cbSSangeeta Misra 		    "status", &enable));
244dbed73cbSSangeeta Misra 	default:
245dbed73cbSSangeeta Misra 		logdebug("i_ilbd_save_rule: invalid scf cmd %d", scf_cmd);
246dbed73cbSSangeeta Misra 		return (ILB_STATUS_INVAL_CMD);
247dbed73cbSSangeeta Misra 	}
248dbed73cbSSangeeta Misra }
249dbed73cbSSangeeta Misra 
250dbed73cbSSangeeta Misra /*
251dbed73cbSSangeeta Misra  * allocate a new daemon-specific rule from the "template" passed
252dbed73cbSSangeeta Misra  * in in *r
253dbed73cbSSangeeta Misra  */
254dbed73cbSSangeeta Misra static ilbd_rule_t *
i_alloc_ilbd_rule(ilb_rule_info_t * r)255dbed73cbSSangeeta Misra i_alloc_ilbd_rule(ilb_rule_info_t *r)
256dbed73cbSSangeeta Misra {
257dbed73cbSSangeeta Misra 	ilbd_rule_t	*rl;
258dbed73cbSSangeeta Misra 
259dbed73cbSSangeeta Misra 	rl = calloc(sizeof (*rl), 1);
260dbed73cbSSangeeta Misra 	if (rl != NULL && r != NULL)
261dbed73cbSSangeeta Misra 		bcopy(r, &rl->irl_info, sizeof (*r));
262dbed73cbSSangeeta Misra 
263dbed73cbSSangeeta Misra 	return (rl);
264dbed73cbSSangeeta Misra }
265dbed73cbSSangeeta Misra 
266dbed73cbSSangeeta Misra static ilbd_rule_t *
i_find_rule_byname(const char * name)267dbed73cbSSangeeta Misra i_find_rule_byname(const char *name)
268dbed73cbSSangeeta Misra {
269dbed73cbSSangeeta Misra 	ilbd_rule_t	*rl;
270dbed73cbSSangeeta Misra 
271dbed73cbSSangeeta Misra 	/* find position of rule in list */
272dbed73cbSSangeeta Misra 	rl = list_head(&ilbd_rule_hlist);
273dbed73cbSSangeeta Misra 	while (rl != NULL &&
274dbed73cbSSangeeta Misra 	    strncmp(rl->irl_name, name, sizeof (rl->irl_name)) != 0) {
275dbed73cbSSangeeta Misra 		rl = list_next(&ilbd_rule_hlist, rl);
276dbed73cbSSangeeta Misra 	}
277dbed73cbSSangeeta Misra 
278dbed73cbSSangeeta Misra 	return (rl);
279dbed73cbSSangeeta Misra }
280dbed73cbSSangeeta Misra 
281dbed73cbSSangeeta Misra /*
282dbed73cbSSangeeta Misra  * get exactly one rule (named in rl->irl_name) data from kernel
283dbed73cbSSangeeta Misra  */
284dbed73cbSSangeeta Misra static ilb_status_t
ilb_get_krule(ilb_rule_info_t * rl)285dbed73cbSSangeeta Misra ilb_get_krule(ilb_rule_info_t *rl)
286dbed73cbSSangeeta Misra {
287dbed73cbSSangeeta Misra 	ilb_status_t	rc;
288dbed73cbSSangeeta Misra 	ilb_rule_cmd_t	kcmd;
289dbed73cbSSangeeta Misra 
290dbed73cbSSangeeta Misra 	kcmd.cmd = ILB_LIST_RULE;
291dbed73cbSSangeeta Misra 	(void) strlcpy(kcmd.name, rl->rl_name, sizeof (kcmd.name));
292dbed73cbSSangeeta Misra 	kcmd.flags = 0;
293dbed73cbSSangeeta Misra 
294dbed73cbSSangeeta Misra 	rc = do_ioctl(&kcmd, 0);
295dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK)
296dbed73cbSSangeeta Misra 		return (rc);
297dbed73cbSSangeeta Misra 
298dbed73cbSSangeeta Misra 	rl->rl_flags = kcmd.flags;
299dbed73cbSSangeeta Misra 	rl->rl_ipversion = IPPROTO_2_AF(kcmd.ip_ver);
300dbed73cbSSangeeta Misra 	rl->rl_vip = kcmd.vip;
301dbed73cbSSangeeta Misra 	rl->rl_proto = kcmd.proto;
302dbed73cbSSangeeta Misra 	rl->rl_minport = kcmd.min_port;
303dbed73cbSSangeeta Misra 	rl->rl_maxport = kcmd.max_port;
304dbed73cbSSangeeta Misra 	rl->rl_algo = algo_impl2lib(kcmd.algo);
305dbed73cbSSangeeta Misra 	rl->rl_topo = topo_impl2lib(kcmd.topo);
306dbed73cbSSangeeta Misra 	rl->rl_stickymask = kcmd.sticky_mask;
307dbed73cbSSangeeta Misra 	rl->rl_nat_src_start = kcmd.nat_src_start;
308dbed73cbSSangeeta Misra 	rl->rl_nat_src_end = kcmd.nat_src_end;
309dbed73cbSSangeeta Misra 	(void) strlcpy(rl->rl_name, kcmd.name, sizeof (rl->rl_name));
310dbed73cbSSangeeta Misra 	rl->rl_conndrain = kcmd.conn_drain_timeout;
311dbed73cbSSangeeta Misra 	rl->rl_nat_timeout = kcmd.nat_expiry;
312dbed73cbSSangeeta Misra 	rl->rl_sticky_timeout = kcmd.sticky_expiry;
313dbed73cbSSangeeta Misra 
314dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
315dbed73cbSSangeeta Misra }
316dbed73cbSSangeeta Misra 
317dbed73cbSSangeeta Misra ilb_status_t
ilbd_retrieve_rule(ilbd_name_t rl_name,uint32_t * rbuf,size_t * rbufsz)318dbed73cbSSangeeta Misra ilbd_retrieve_rule(ilbd_name_t rl_name, uint32_t *rbuf, size_t *rbufsz)
319dbed73cbSSangeeta Misra {
320dbed73cbSSangeeta Misra 	ilbd_rule_t	*irl = NULL;
321dbed73cbSSangeeta Misra 	ilb_status_t	rc;
322dbed73cbSSangeeta Misra 	ilb_rule_info_t	*rinfo;
323dbed73cbSSangeeta Misra 
324dbed73cbSSangeeta Misra 	irl = i_find_rule_byname(rl_name);
325dbed73cbSSangeeta Misra 	if (irl == NULL)
326dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
327dbed73cbSSangeeta Misra 
328dbed73cbSSangeeta Misra 	ilbd_reply_ok(rbuf, rbufsz);
329dbed73cbSSangeeta Misra 	rinfo = (ilb_rule_info_t *)&((ilb_comm_t *)rbuf)->ic_data;
330dbed73cbSSangeeta Misra 	bcopy(&irl->irl_info, rinfo, sizeof (*rinfo));
331dbed73cbSSangeeta Misra 
332dbed73cbSSangeeta Misra 	/*
333dbed73cbSSangeeta Misra 	 * Check if the various timeout values are 0.  If one is, get the
334dbed73cbSSangeeta Misra 	 * default values from kernel.
335dbed73cbSSangeeta Misra 	 */
336dbed73cbSSangeeta Misra 	if (rinfo->rl_conndrain == 0 || rinfo->rl_nat_timeout == 0 ||
337dbed73cbSSangeeta Misra 	    rinfo->rl_sticky_timeout == 0) {
338dbed73cbSSangeeta Misra 		ilb_rule_info_t tmp_info;
339dbed73cbSSangeeta Misra 
340dbed73cbSSangeeta Misra 		(void) strcpy(tmp_info.rl_name, rinfo->rl_name);
341dbed73cbSSangeeta Misra 		rc = ilb_get_krule(&tmp_info);
342dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
343dbed73cbSSangeeta Misra 			return (rc);
344dbed73cbSSangeeta Misra 		if (rinfo->rl_conndrain == 0)
345dbed73cbSSangeeta Misra 			rinfo->rl_conndrain = tmp_info.rl_conndrain;
3462c2d21e9SRichard Lowe 		if ((rinfo->rl_topo == ILB_TOPO_NAT ||
3472c2d21e9SRichard Lowe 		    rinfo->rl_topo == ILB_TOPO_HALF_NAT) &&
348dbed73cbSSangeeta Misra 		    rinfo->rl_nat_timeout == 0) {
349dbed73cbSSangeeta Misra 			rinfo->rl_nat_timeout = tmp_info.rl_nat_timeout;
350dbed73cbSSangeeta Misra 		}
351dbed73cbSSangeeta Misra 		if ((rinfo->rl_flags & ILB_FLAGS_RULE_STICKY) &&
352dbed73cbSSangeeta Misra 		    rinfo->rl_sticky_timeout == 0) {
353dbed73cbSSangeeta Misra 			rinfo->rl_sticky_timeout = tmp_info.rl_sticky_timeout;
354dbed73cbSSangeeta Misra 		}
355dbed73cbSSangeeta Misra 	}
356dbed73cbSSangeeta Misra 	*rbufsz += sizeof (ilb_rule_info_t);
357dbed73cbSSangeeta Misra 
358dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
359dbed73cbSSangeeta Misra }
360dbed73cbSSangeeta Misra 
361dbed73cbSSangeeta Misra static ilb_status_t
ilbd_destroy_one_rule(ilbd_rule_t * irl)362dbed73cbSSangeeta Misra ilbd_destroy_one_rule(ilbd_rule_t *irl)
363dbed73cbSSangeeta Misra {
364dbed73cbSSangeeta Misra 	ilb_status_t	rc;
365dbed73cbSSangeeta Misra 	ilb_name_cmd_t	kcmd;
366dbed73cbSSangeeta Misra 
367dbed73cbSSangeeta Misra 	/*
368dbed73cbSSangeeta Misra 	 * as far as talking to the kernel is concerned, "all rules"
369dbed73cbSSangeeta Misra 	 * is handled in one go somewhere else, so we only
370dbed73cbSSangeeta Misra 	 * tell the kernel about single rules here.
371dbed73cbSSangeeta Misra 	 */
372dbed73cbSSangeeta Misra 	if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) {
373dbed73cbSSangeeta Misra 		kcmd.cmd = ILB_DESTROY_RULE;
374dbed73cbSSangeeta Misra 		(void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name));
375dbed73cbSSangeeta Misra 		kcmd.flags = 0;
376dbed73cbSSangeeta Misra 
377dbed73cbSSangeeta Misra 		rc = do_ioctl(&kcmd, 0);
378dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
379dbed73cbSSangeeta Misra 			return (rc);
380dbed73cbSSangeeta Misra 
381dbed73cbSSangeeta Misra 	}
382dbed73cbSSangeeta Misra 	list_remove(&irl->irl_sg->isg_rulelist, irl);
383dbed73cbSSangeeta Misra 	list_remove(&ilbd_rule_hlist, irl);
384dbed73cbSSangeeta Misra 
385dbed73cbSSangeeta Misra 	/*
386dbed73cbSSangeeta Misra 	 * When dissociating a rule, only two errors can happen.  The hc
387dbed73cbSSangeeta Misra 	 * name is incorrect or the rule is not associated with the hc
388dbed73cbSSangeeta Misra 	 * object.  Both should not happen....  The check is for debugging
389dbed73cbSSangeeta Misra 	 * purpose.
390dbed73cbSSangeeta Misra 	 */
391dbed73cbSSangeeta Misra 	if (RULE_HAS_HC(irl) && (rc = ilbd_hc_dissociate_rule(irl)) !=
392dbed73cbSSangeeta Misra 	    ILB_STATUS_OK) {
393dbed73cbSSangeeta Misra 		logerr("ilbd_destroy_one_rule: cannot "
394dbed73cbSSangeeta Misra 		    "dissociate %s from hc object %s: %d",
395dbed73cbSSangeeta Misra 		    irl->irl_name, irl->irl_hcname, rc);
396dbed73cbSSangeeta Misra 	}
397dbed73cbSSangeeta Misra 
398dbed73cbSSangeeta Misra 	rc = i_ilbd_save_rule(irl, ILBD_SCF_DESTROY);
399dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK)
400dbed73cbSSangeeta Misra 		logdebug("ilbd_destroy_rule: save rule failed");
401dbed73cbSSangeeta Misra 
402dbed73cbSSangeeta Misra 	free(irl);
403dbed73cbSSangeeta Misra 	return (rc);
404dbed73cbSSangeeta Misra }
405dbed73cbSSangeeta Misra 
406dbed73cbSSangeeta Misra /*
407dbed73cbSSangeeta Misra  * the following two functions are the other's opposite, and can
408dbed73cbSSangeeta Misra  * call into each other for roll back purposes in case of error.
409dbed73cbSSangeeta Misra  * To avoid endless recursion, the 'is_rollback' parameter must be
410dbed73cbSSangeeta Misra  * set to B_TRUE in the roll back case.
411dbed73cbSSangeeta Misra  */
412dbed73cbSSangeeta Misra static ilb_status_t
ilbd_enable_one_rule(ilbd_rule_t * irl,boolean_t is_rollback)413dbed73cbSSangeeta Misra ilbd_enable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback)
414dbed73cbSSangeeta Misra {
415dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
416dbed73cbSSangeeta Misra 	ilb_name_cmd_t	kcmd;
417dbed73cbSSangeeta Misra 
418dbed73cbSSangeeta Misra 	/* no use sending a no-op to the kernel */
419dbed73cbSSangeeta Misra 	if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) != 0)
420dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
421dbed73cbSSangeeta Misra 
422dbed73cbSSangeeta Misra 	irl->irl_flags |= ILB_FLAGS_RULE_ENABLED;
423dbed73cbSSangeeta Misra 
424dbed73cbSSangeeta Misra 	/* "all rules" is handled in one go somewhere else, not here */
425dbed73cbSSangeeta Misra 	if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) {
426dbed73cbSSangeeta Misra 		kcmd.cmd = ILB_ENABLE_RULE;
427dbed73cbSSangeeta Misra 		(void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name));
428dbed73cbSSangeeta Misra 		kcmd.flags = 0;
429dbed73cbSSangeeta Misra 
430dbed73cbSSangeeta Misra 		rc = do_ioctl(&kcmd, 0);
431dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
432dbed73cbSSangeeta Misra 			return (rc);
433dbed73cbSSangeeta Misra 	}
434dbed73cbSSangeeta Misra 	if (RULE_HAS_HC(irl) && (rc = ilbd_hc_enable_rule(irl)) !=
435dbed73cbSSangeeta Misra 	    ILB_STATUS_OK) {
436dbed73cbSSangeeta Misra 		/* Undo the kernel work */
437dbed73cbSSangeeta Misra 		kcmd.cmd = ILB_DISABLE_RULE;
438dbed73cbSSangeeta Misra 		/* Cannot do much if ioctl fails... */
439dbed73cbSSangeeta Misra 		(void) do_ioctl(&kcmd, 0);
440dbed73cbSSangeeta Misra 		return (rc);
441dbed73cbSSangeeta Misra 	}
442dbed73cbSSangeeta Misra 
443dbed73cbSSangeeta Misra 	if (!is_rollback) {
444dbed73cbSSangeeta Misra 		if (rc == ILB_STATUS_OK)
445dbed73cbSSangeeta Misra 			rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE);
446dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
447dbed73cbSSangeeta Misra 			/* ignore rollback return code */
448dbed73cbSSangeeta Misra 			(void) ilbd_disable_one_rule(irl, B_TRUE);
449dbed73cbSSangeeta Misra 	}
450dbed73cbSSangeeta Misra 
451dbed73cbSSangeeta Misra 	return (rc);
452dbed73cbSSangeeta Misra }
453dbed73cbSSangeeta Misra 
454dbed73cbSSangeeta Misra static ilb_status_t
ilbd_disable_one_rule(ilbd_rule_t * irl,boolean_t is_rollback)455dbed73cbSSangeeta Misra ilbd_disable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback)
456dbed73cbSSangeeta Misra {
457dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
458dbed73cbSSangeeta Misra 	ilb_name_cmd_t	kcmd;
459dbed73cbSSangeeta Misra 
460dbed73cbSSangeeta Misra 	/* no use sending a no-op to the kernel */
461dbed73cbSSangeeta Misra 	if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) == 0)
462dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
463dbed73cbSSangeeta Misra 
464dbed73cbSSangeeta Misra 	irl->irl_flags &= ~ILB_FLAGS_RULE_ENABLED;
465dbed73cbSSangeeta Misra 
466dbed73cbSSangeeta Misra 	/* "all rules" is handled in one go somewhere else, not here */
467dbed73cbSSangeeta Misra 	if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) {
468dbed73cbSSangeeta Misra 		kcmd.cmd = ILB_DISABLE_RULE;
469dbed73cbSSangeeta Misra 		(void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name));
470dbed73cbSSangeeta Misra 		kcmd.flags = 0;
471dbed73cbSSangeeta Misra 
472dbed73cbSSangeeta Misra 		rc = do_ioctl(&kcmd, 0);
473dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
474dbed73cbSSangeeta Misra 			return (rc);
475dbed73cbSSangeeta Misra 	}
476dbed73cbSSangeeta Misra 
477dbed73cbSSangeeta Misra 	if (RULE_HAS_HC(irl) && (rc = ilbd_hc_disable_rule(irl)) !=
478dbed73cbSSangeeta Misra 	    ILB_STATUS_OK) {
479dbed73cbSSangeeta Misra 		/* Undo the kernel work */
480dbed73cbSSangeeta Misra 		kcmd.cmd = ILB_ENABLE_RULE;
481dbed73cbSSangeeta Misra 		/* Cannot do much if ioctl fails... */
482dbed73cbSSangeeta Misra 		(void) do_ioctl(&kcmd, 0);
483dbed73cbSSangeeta Misra 		return (rc);
484dbed73cbSSangeeta Misra 	}
485dbed73cbSSangeeta Misra 
486dbed73cbSSangeeta Misra 	if (!is_rollback) {
487dbed73cbSSangeeta Misra 		if (rc == ILB_STATUS_OK)
488dbed73cbSSangeeta Misra 			rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE);
489dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
490dbed73cbSSangeeta Misra 			/* ignore rollback return code */
491dbed73cbSSangeeta Misra 			(void) ilbd_enable_one_rule(irl, B_TRUE);
492dbed73cbSSangeeta Misra 	}
493dbed73cbSSangeeta Misra 
494dbed73cbSSangeeta Misra 	return (rc);
495dbed73cbSSangeeta Misra }
496dbed73cbSSangeeta Misra 
497dbed73cbSSangeeta Misra /*
498dbed73cbSSangeeta Misra  * Generates an audit record for a supplied rule name
499dbed73cbSSangeeta Misra  * Used for enable_rule, disable_rule, delete_rule,
500dbed73cbSSangeeta Misra  * and create_rule subcommands
501dbed73cbSSangeeta Misra  */
502dbed73cbSSangeeta Misra static void
ilbd_audit_rule_event(const char * audit_rule_name,ilb_rule_info_t * rlinfo,ilbd_cmd_t cmd,ilb_status_t rc,ucred_t * ucredp)503dbed73cbSSangeeta Misra ilbd_audit_rule_event(const char *audit_rule_name,
504dbed73cbSSangeeta Misra     ilb_rule_info_t *rlinfo, ilbd_cmd_t cmd, ilb_status_t rc,
505dbed73cbSSangeeta Misra     ucred_t *ucredp)
506dbed73cbSSangeeta Misra {
507dbed73cbSSangeeta Misra 	adt_session_data_t	*ah;
508dbed73cbSSangeeta Misra 	adt_event_data_t	*event;
509dbed73cbSSangeeta Misra 	au_event_t		flag;
510dbed73cbSSangeeta Misra 	int			scf_val_len = ILBD_MAX_VALUE_LEN;
5113ae6a67dSSangeeta Misra 	char			*aobuf = NULL; /* algo:topo */
5123ae6a67dSSangeeta Misra 	char			*valstr1 = NULL;
5133ae6a67dSSangeeta Misra 	char			*valstr2 = NULL;
5143ae6a67dSSangeeta Misra 	char			pbuf[PROTOCOL_LEN]; /* protocol */
5153ae6a67dSSangeeta Misra 	char			hcpbuf[PORT_LEN]; /* hcport */
516dbed73cbSSangeeta Misra 	int			audit_error;
517dbed73cbSSangeeta Misra 
518dbed73cbSSangeeta Misra 	if ((ucredp == NULL) && (cmd == ILBD_CREATE_RULE))  {
519dbed73cbSSangeeta Misra 		/*
520dbed73cbSSangeeta Misra 		 * we came here from the path where ilbd incorporates
521dbed73cbSSangeeta Misra 		 * the configuration that is listed in SCF :
522dbed73cbSSangeeta Misra 		 * i_ilbd_read_config->ilbd_walk_rule_pgs->
523dbed73cbSSangeeta Misra 		 *    ->ilbd_scf_instance_walk_pg->ilbd_create_rule
524dbed73cbSSangeeta Misra 		 * We skip auditing in that case
525dbed73cbSSangeeta Misra 		 */
526dbed73cbSSangeeta Misra 		return;
527dbed73cbSSangeeta Misra 	}
528dbed73cbSSangeeta Misra 	if (adt_start_session(&ah, NULL, 0) != 0) {
529dbed73cbSSangeeta Misra 		logerr("ilbd_audit_rule_event: adt_start_session failed");
530dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
531dbed73cbSSangeeta Misra 	}
532dbed73cbSSangeeta Misra 	if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) {
533dbed73cbSSangeeta Misra 		(void) adt_end_session(ah);
534dbed73cbSSangeeta Misra 		logerr("ilbd_audit_rule_event: adt_set_from_ucred failed");
535dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
536dbed73cbSSangeeta Misra 	}
537dbed73cbSSangeeta Misra 	if (cmd == ILBD_ENABLE_RULE)
538dbed73cbSSangeeta Misra 		flag = ADT_ilb_enable_rule;
539dbed73cbSSangeeta Misra 	else if (cmd == ILBD_DISABLE_RULE)
540dbed73cbSSangeeta Misra 		flag = ADT_ilb_disable_rule;
541dbed73cbSSangeeta Misra 	else if (cmd == ILBD_DESTROY_RULE)
542dbed73cbSSangeeta Misra 		flag = ADT_ilb_delete_rule;
543dbed73cbSSangeeta Misra 	else if (cmd == ILBD_CREATE_RULE)
544dbed73cbSSangeeta Misra 		flag = ADT_ilb_create_rule;
545dbed73cbSSangeeta Misra 
546dbed73cbSSangeeta Misra 	if ((event = adt_alloc_event(ah, flag)) == NULL) {
547dbed73cbSSangeeta Misra 		logerr("ilbd_audit_rule_event: adt_alloc_event failed");
548dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
549dbed73cbSSangeeta Misra 	}
550dbed73cbSSangeeta Misra 
551dbed73cbSSangeeta Misra 	(void) memset((char *)event, 0, sizeof (adt_event_data_t));
552dbed73cbSSangeeta Misra 
553dbed73cbSSangeeta Misra 	switch (cmd) {
554dbed73cbSSangeeta Misra 	case ILBD_DESTROY_RULE:
555dbed73cbSSangeeta Misra 		event->adt_ilb_delete_rule.auth_used = NET_ILB_CONFIG_AUTH;
556dbed73cbSSangeeta Misra 		event->adt_ilb_delete_rule.rule_name = (char *)audit_rule_name;
557dbed73cbSSangeeta Misra 		break;
558dbed73cbSSangeeta Misra 	case ILBD_ENABLE_RULE:
559dbed73cbSSangeeta Misra 		event->adt_ilb_enable_rule.auth_used = NET_ILB_ENABLE_AUTH;
560dbed73cbSSangeeta Misra 		event->adt_ilb_enable_rule.rule_name = (char *)audit_rule_name;
561dbed73cbSSangeeta Misra 		break;
562dbed73cbSSangeeta Misra 	case ILBD_DISABLE_RULE:
563dbed73cbSSangeeta Misra 		event->adt_ilb_disable_rule.auth_used = NET_ILB_ENABLE_AUTH;
564dbed73cbSSangeeta Misra 		event->adt_ilb_disable_rule.rule_name = (char *)audit_rule_name;
565dbed73cbSSangeeta Misra 		break;
566dbed73cbSSangeeta Misra 	case ILBD_CREATE_RULE:
5673ae6a67dSSangeeta Misra 		if (((aobuf = malloc(scf_val_len)) == NULL) ||
5683ae6a67dSSangeeta Misra 		    ((valstr1 = malloc(scf_val_len)) == NULL) ||
5693ae6a67dSSangeeta Misra 		    ((valstr2 = malloc(scf_val_len)) == NULL)) {
5703ae6a67dSSangeeta Misra 			logerr("ilbd_audit_rule_event: could not"
5713ae6a67dSSangeeta Misra 			    " allocate buffer");
5723ae6a67dSSangeeta Misra 			exit(EXIT_FAILURE);
5733ae6a67dSSangeeta Misra 		}
574dbed73cbSSangeeta Misra 
575dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.auth_used = NET_ILB_CONFIG_AUTH;
576dbed73cbSSangeeta Misra 
5775df82708SSangeeta Misra 		/* Fill in virtual IP address type */
5785df82708SSangeeta Misra 		if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_vip)) {
5795df82708SSangeeta Misra 			event->adt_ilb_create_rule.virtual_ipaddress_type =
5805df82708SSangeeta Misra 			    ADT_IPv4;
5815df82708SSangeeta Misra 			cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress,
5825df82708SSangeeta Misra 			    ADT_IPv4, rlinfo->rl_vip);
5835df82708SSangeeta Misra 		} else {
5845df82708SSangeeta Misra 			event->adt_ilb_create_rule.virtual_ipaddress_type =
5855df82708SSangeeta Misra 			    ADT_IPv6;
5865df82708SSangeeta Misra 			cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress,
5875df82708SSangeeta Misra 			    ADT_IPv6, rlinfo->rl_vip);
5885df82708SSangeeta Misra 		}
589dbed73cbSSangeeta Misra 		/* Fill in port - could be a single value or a range */
590dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.min_port = ntohs(rlinfo->rl_minport);
591dbed73cbSSangeeta Misra 		if (ntohs(rlinfo->rl_maxport) > ntohs(rlinfo->rl_minport)) {
592dbed73cbSSangeeta Misra 			/* port range */
593dbed73cbSSangeeta Misra 			event->adt_ilb_create_rule.max_port =
594dbed73cbSSangeeta Misra 			    ntohs(rlinfo->rl_maxport);
595dbed73cbSSangeeta Misra 		} else {
596dbed73cbSSangeeta Misra 			/* in audit record, max=min when single port */
597dbed73cbSSangeeta Misra 			event->adt_ilb_create_rule.max_port =
598dbed73cbSSangeeta Misra 			    ntohs(rlinfo->rl_minport);
599dbed73cbSSangeeta Misra 		}
600dbed73cbSSangeeta Misra 
601dbed73cbSSangeeta Misra 		/*
602dbed73cbSSangeeta Misra 		 * Fill in  protocol - if user does not specify it,
603dbed73cbSSangeeta Misra 		 * its TCP by default
604dbed73cbSSangeeta Misra 		 */
605dbed73cbSSangeeta Misra 		if (rlinfo->rl_proto == IPPROTO_UDP)
6063ae6a67dSSangeeta Misra 			(void) snprintf(pbuf, PROTOCOL_LEN, "UDP");
607dbed73cbSSangeeta Misra 		else
6083ae6a67dSSangeeta Misra 			(void) snprintf(pbuf, PROTOCOL_LEN, "TCP");
609dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.protocol = pbuf;
610dbed73cbSSangeeta Misra 
611dbed73cbSSangeeta Misra 		/* Fill in algorithm and operation type */
612dbed73cbSSangeeta Misra 		ilbd_algo_to_str(rlinfo->rl_algo, valstr1);
613dbed73cbSSangeeta Misra 		ilbd_topo_to_str(rlinfo->rl_topo, valstr2);
6143ae6a67dSSangeeta Misra 		(void) snprintf(aobuf, scf_val_len, "%s:%s",
615dbed73cbSSangeeta Misra 		    valstr1, valstr2);
616dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.algo_optype = aobuf;
617dbed73cbSSangeeta Misra 
618dbed73cbSSangeeta Misra 		/* Fill in proxy-src for the NAT case */
619dbed73cbSSangeeta Misra 		if (rlinfo->rl_topo == ILB_TOPO_NAT)  {
6205df82708SSangeeta Misra 			/* copy starting proxy-src address */
6215df82708SSangeeta Misra 			if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_start)) {
6225df82708SSangeeta Misra 				/* V4 case */
6235df82708SSangeeta Misra 				event->adt_ilb_create_rule.proxy_src_min_type =
6245df82708SSangeeta Misra 				    ADT_IPv4;
6255df82708SSangeeta Misra 				cvt_addr(
6265df82708SSangeeta Misra 				    event->adt_ilb_create_rule.proxy_src_min,
6275df82708SSangeeta Misra 				    ADT_IPv4, rlinfo->rl_nat_src_start);
6285df82708SSangeeta Misra 			} else {
6295df82708SSangeeta Misra 				/* V6 case */
6305df82708SSangeeta Misra 				event->adt_ilb_create_rule.proxy_src_min_type =
6315df82708SSangeeta Misra 				    ADT_IPv6;
6325df82708SSangeeta Misra 				cvt_addr(
6335df82708SSangeeta Misra 				    event->adt_ilb_create_rule.proxy_src_min,
6345df82708SSangeeta Misra 				    ADT_IPv6, rlinfo->rl_nat_src_start);
6355df82708SSangeeta Misra 			}
6365df82708SSangeeta Misra 
6375df82708SSangeeta Misra 			/* copy ending proxy-src address */
638*9e1bdc14SToomas Soome 			if (IN6_IS_ADDR_UNSPECIFIED(&rlinfo->rl_nat_src_end)) {
6395df82708SSangeeta Misra 				/* proxy-src is a single address */
6405df82708SSangeeta Misra 				event->adt_ilb_create_rule.proxy_src_max_type =
6415df82708SSangeeta Misra 				    event->
6425df82708SSangeeta Misra 				    adt_ilb_create_rule.proxy_src_min_type;
6435df82708SSangeeta Misra 				(void) memcpy(
6445df82708SSangeeta Misra 				    event->adt_ilb_create_rule.proxy_src_max,
6455df82708SSangeeta Misra 				    event->adt_ilb_create_rule.proxy_src_min,
6465df82708SSangeeta Misra 				    (4 * sizeof (uint32_t)));
6475df82708SSangeeta Misra 			} else if (
6485df82708SSangeeta Misra 			    IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_end)) {
6495df82708SSangeeta Misra 				/*
6505df82708SSangeeta Misra 				 * proxy-src is a address range - copy ending
6515df82708SSangeeta Misra 				 * proxy-src address
6525df82708SSangeeta Misra 				 * V4 case
6535df82708SSangeeta Misra 				 */
6545df82708SSangeeta Misra 				event->adt_ilb_create_rule.proxy_src_max_type =
6555df82708SSangeeta Misra 				    ADT_IPv4;
6565df82708SSangeeta Misra 				cvt_addr(
6575df82708SSangeeta Misra 				    event->adt_ilb_create_rule.proxy_src_max,
6585df82708SSangeeta Misra 				    ADT_IPv4, rlinfo->rl_nat_src_end);
659dbed73cbSSangeeta Misra 			} else {
6605df82708SSangeeta Misra 				/* V6 case */
6615df82708SSangeeta Misra 				event->adt_ilb_create_rule.proxy_src_max_type =
6625df82708SSangeeta Misra 				    ADT_IPv6;
6635df82708SSangeeta Misra 				cvt_addr(
6645df82708SSangeeta Misra 				    event->adt_ilb_create_rule.proxy_src_max,
6655df82708SSangeeta Misra 				    ADT_IPv6, rlinfo->rl_nat_src_end);
666dbed73cbSSangeeta Misra 			}
667dbed73cbSSangeeta Misra 		}
668dbed73cbSSangeeta Misra 
669dbed73cbSSangeeta Misra 		/*
670dbed73cbSSangeeta Misra 		 * Fill in pmask if user has specified one - 0 means
671dbed73cbSSangeeta Misra 		 * no persistence
672dbed73cbSSangeeta Misra 		 */
673dbed73cbSSangeeta Misra 		valstr1[0] = '\0';
674dbed73cbSSangeeta Misra 		ilbd_ip_to_str(rlinfo->rl_ipversion, &rlinfo->rl_stickymask,
675dbed73cbSSangeeta Misra 		    valstr1);
676dbed73cbSSangeeta Misra 			event->adt_ilb_create_rule.persist_mask = valstr1;
677dbed73cbSSangeeta Misra 
678dbed73cbSSangeeta Misra 		/* If there is a hcname */
679dbed73cbSSangeeta Misra 		if (rlinfo->rl_hcname[0] != '\0')
680dbed73cbSSangeeta Misra 			event->adt_ilb_create_rule.hcname = rlinfo->rl_hcname;
681dbed73cbSSangeeta Misra 
682dbed73cbSSangeeta Misra 		/* Fill in hcport */
683dbed73cbSSangeeta Misra 		if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_FIX) {
684dbed73cbSSangeeta Misra 			/* hcport is specified by user */
6853ae6a67dSSangeeta Misra 			(void) snprintf(hcpbuf, PORT_LEN, "%d",
686dbed73cbSSangeeta Misra 			    rlinfo->rl_hcport);
687dbed73cbSSangeeta Misra 			event->adt_ilb_create_rule.hcport = hcpbuf;
688dbed73cbSSangeeta Misra 		} else if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_ANY) {
689dbed73cbSSangeeta Misra 			/* user has specified "ANY" */
6903ae6a67dSSangeeta Misra 			(void) snprintf(hcpbuf, PORT_LEN, "ANY");
691dbed73cbSSangeeta Misra 			event->adt_ilb_create_rule.hcport = hcpbuf;
692dbed73cbSSangeeta Misra 		}
693dbed73cbSSangeeta Misra 		/*
694dbed73cbSSangeeta Misra 		 * Fill out the conndrain, nat_timeout and persist_timeout
695dbed73cbSSangeeta Misra 		 * If the user does not specify them, the default value
696dbed73cbSSangeeta Misra 		 * is set in the kernel. Userland does not know what
697dbed73cbSSangeeta Misra 		 * the values are. So if the user
698dbed73cbSSangeeta Misra 		 * does not specify these values they will show up as
699dbed73cbSSangeeta Misra 		 * 0 in the audit record.
700dbed73cbSSangeeta Misra 		 */
701dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.conndrain_timeout =
702dbed73cbSSangeeta Misra 		    rlinfo->rl_conndrain;
703dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.nat_timeout =
704dbed73cbSSangeeta Misra 		    rlinfo->rl_nat_timeout;
705dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.persist_timeout =
706dbed73cbSSangeeta Misra 		    rlinfo->rl_sticky_timeout;
707dbed73cbSSangeeta Misra 
708dbed73cbSSangeeta Misra 		/* Fill out servergroup and rule name */
709dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.server_group = rlinfo->rl_sgname;
710dbed73cbSSangeeta Misra 		event->adt_ilb_create_rule.rule_name = rlinfo->rl_name;
711dbed73cbSSangeeta Misra 		break;
712dbed73cbSSangeeta Misra 	}
713dbed73cbSSangeeta Misra 	if (rc == ILB_STATUS_OK) {
714dbed73cbSSangeeta Misra 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
715dbed73cbSSangeeta Misra 			logerr("ilbd_audit_rule_event:adt_put_event failed");
716dbed73cbSSangeeta Misra 			exit(EXIT_FAILURE);
717dbed73cbSSangeeta Misra 		}
718dbed73cbSSangeeta Misra 	} else {
719dbed73cbSSangeeta Misra 		audit_error = ilberror2auditerror(rc);
720dbed73cbSSangeeta Misra 		if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) {
721dbed73cbSSangeeta Misra 			logerr("ilbd_audit_rule_event: adt_put_event failed");
722dbed73cbSSangeeta Misra 			exit(EXIT_FAILURE);
723dbed73cbSSangeeta Misra 		}
724dbed73cbSSangeeta Misra 	}
725dbed73cbSSangeeta Misra 	adt_free_event(event);
7263ae6a67dSSangeeta Misra 	free(aobuf);
7273ae6a67dSSangeeta Misra 	free(valstr1);
7283ae6a67dSSangeeta Misra 	free(valstr2);
729dbed73cbSSangeeta Misra 	(void) adt_end_session(ah);
730dbed73cbSSangeeta Misra }
7315df82708SSangeeta Misra /*
7325df82708SSangeeta Misra  * converts IP address from in6_addr format to uint32_t[4]
7335df82708SSangeeta Misra  * This conversion is needed for recording IP address in
7345df82708SSangeeta Misra  * audit records.
7355df82708SSangeeta Misra  */
7365df82708SSangeeta Misra void
cvt_addr(uint32_t * audit,int32_t type,struct in6_addr address)7375df82708SSangeeta Misra cvt_addr(uint32_t *audit, int32_t type, struct in6_addr address)
7385df82708SSangeeta Misra {
7395df82708SSangeeta Misra 
7405df82708SSangeeta Misra 	if (type == ADT_IPv4)  {
7415df82708SSangeeta Misra 		/* address is IPv4 */
7425df82708SSangeeta Misra 		audit[0] = address._S6_un._S6_u32[3];
7435df82708SSangeeta Misra 	} else {
7445df82708SSangeeta Misra 		/* address is IPv6 */
7455df82708SSangeeta Misra 		(void) memcpy(audit, address._S6_un._S6_u32,
7465df82708SSangeeta Misra 		    (4 * sizeof (uint32_t)));
7475df82708SSangeeta Misra 	}
7485df82708SSangeeta Misra }
749dbed73cbSSangeeta Misra 
750dbed73cbSSangeeta Misra static ilb_status_t
i_ilbd_action_switch(ilbd_rule_t * irl,ilbd_cmd_t cmd,boolean_t is_rollback,ucred_t * ucredp)751dbed73cbSSangeeta Misra i_ilbd_action_switch(ilbd_rule_t *irl, ilbd_cmd_t cmd,
752dbed73cbSSangeeta Misra     boolean_t is_rollback, ucred_t *ucredp)
753dbed73cbSSangeeta Misra {
754dbed73cbSSangeeta Misra 	ilb_status_t    rc;
755dbed73cbSSangeeta Misra 
756dbed73cbSSangeeta Misra 	switch (cmd) {
757dbed73cbSSangeeta Misra 	case ILBD_DESTROY_RULE:
758dbed73cbSSangeeta Misra 		rc = ilbd_destroy_one_rule(irl);
759dbed73cbSSangeeta Misra 		if (!is_rollback) {
760dbed73cbSSangeeta Misra 			ilbd_audit_rule_event(irl->irl_name, NULL,
761dbed73cbSSangeeta Misra 			    cmd, rc, ucredp);
762dbed73cbSSangeeta Misra 		}
763dbed73cbSSangeeta Misra 		return (rc);
764dbed73cbSSangeeta Misra 	case ILBD_ENABLE_RULE:
765dbed73cbSSangeeta Misra 		rc = ilbd_enable_one_rule(irl, is_rollback);
766dbed73cbSSangeeta Misra 		if (!is_rollback) {
767dbed73cbSSangeeta Misra 			ilbd_audit_rule_event(irl->irl_name, NULL, cmd,
768dbed73cbSSangeeta Misra 			    rc, ucredp);
769dbed73cbSSangeeta Misra 		}
770dbed73cbSSangeeta Misra 		return (rc);
771dbed73cbSSangeeta Misra 	case ILBD_DISABLE_RULE:
772dbed73cbSSangeeta Misra 		rc = ilbd_disable_one_rule(irl, is_rollback);
773dbed73cbSSangeeta Misra 		if (!is_rollback) {
774dbed73cbSSangeeta Misra 			ilbd_audit_rule_event(irl->irl_name, NULL, cmd,
775dbed73cbSSangeeta Misra 			    rc, ucredp);
776dbed73cbSSangeeta Misra 		}
777dbed73cbSSangeeta Misra 		return (rc);
778dbed73cbSSangeeta Misra 	}
779dbed73cbSSangeeta Misra 	return (ILB_STATUS_INVAL_CMD);
780dbed73cbSSangeeta Misra }
781dbed73cbSSangeeta Misra 
782dbed73cbSSangeeta Misra static ilb_cmd_t
i_ilbd2ilb_cmd(ilbd_cmd_t c)783dbed73cbSSangeeta Misra i_ilbd2ilb_cmd(ilbd_cmd_t c)
784dbed73cbSSangeeta Misra {
785dbed73cbSSangeeta Misra 	ilb_cmd_t	r;
786dbed73cbSSangeeta Misra 
787dbed73cbSSangeeta Misra 	switch (c) {
788dbed73cbSSangeeta Misra 	case ILBD_CREATE_RULE:
789dbed73cbSSangeeta Misra 		r = ILB_CREATE_RULE;
790dbed73cbSSangeeta Misra 		break;
791dbed73cbSSangeeta Misra 	case ILBD_DESTROY_RULE:
792dbed73cbSSangeeta Misra 		r = ILB_DESTROY_RULE;
793dbed73cbSSangeeta Misra 		break;
794dbed73cbSSangeeta Misra 	case ILBD_ENABLE_RULE:
795dbed73cbSSangeeta Misra 		r = ILB_ENABLE_RULE;
796dbed73cbSSangeeta Misra 		break;
797dbed73cbSSangeeta Misra 	case ILBD_DISABLE_RULE:
798dbed73cbSSangeeta Misra 		r = ILB_DISABLE_RULE;
799dbed73cbSSangeeta Misra 		break;
800dbed73cbSSangeeta Misra 	}
801dbed73cbSSangeeta Misra 	return (r);
802dbed73cbSSangeeta Misra }
803dbed73cbSSangeeta Misra 
804dbed73cbSSangeeta Misra static ilbd_cmd_t
get_undo_cmd(ilbd_cmd_t cmd)805dbed73cbSSangeeta Misra get_undo_cmd(ilbd_cmd_t cmd)
806dbed73cbSSangeeta Misra {
807dbed73cbSSangeeta Misra 	ilbd_cmd_t	u_cmd;
808dbed73cbSSangeeta Misra 
809dbed73cbSSangeeta Misra 	switch (cmd) {
810dbed73cbSSangeeta Misra 	case ILBD_DESTROY_RULE:
811dbed73cbSSangeeta Misra 		u_cmd = ILBD_BAD_CMD;
812dbed73cbSSangeeta Misra 		break;
813dbed73cbSSangeeta Misra 	case ILBD_ENABLE_RULE:
814dbed73cbSSangeeta Misra 		u_cmd = ILBD_DISABLE_RULE;
815dbed73cbSSangeeta Misra 		break;
816dbed73cbSSangeeta Misra 	case ILBD_DISABLE_RULE:
817dbed73cbSSangeeta Misra 		u_cmd = ILBD_ENABLE_RULE;
818dbed73cbSSangeeta Misra 		break;
819dbed73cbSSangeeta Misra 	}
820dbed73cbSSangeeta Misra 
821dbed73cbSSangeeta Misra 	return (u_cmd);
822dbed73cbSSangeeta Misra }
823dbed73cbSSangeeta Misra 
824dbed73cbSSangeeta Misra static ilb_status_t
i_ilbd_rule_action(const char * rule_name,const struct passwd * ps,ilbd_cmd_t cmd,ucred_t * ucredp)825dbed73cbSSangeeta Misra i_ilbd_rule_action(const char *rule_name, const struct passwd *ps,
826dbed73cbSSangeeta Misra     ilbd_cmd_t cmd, ucred_t *ucredp)
827dbed73cbSSangeeta Misra {
828dbed73cbSSangeeta Misra 	ilbd_rule_t	*irl, *irl_next;
829dbed73cbSSangeeta Misra 	boolean_t	is_all_rules = B_FALSE;
830dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
831dbed73cbSSangeeta Misra 	ilb_name_cmd_t	kcmd;
832dbed73cbSSangeeta Misra 	ilbd_cmd_t	u_cmd;
833dbed73cbSSangeeta Misra 	char    rulename[ILB_NAMESZ];
834dbed73cbSSangeeta Misra 
835dbed73cbSSangeeta Misra 	if (ps != NULL) {
836dbed73cbSSangeeta Misra 		if ((cmd == ILBD_ENABLE_RULE) || (cmd == ILBD_DISABLE_RULE))
837dbed73cbSSangeeta Misra 			rc = ilbd_check_client_enable_auth(ps);
838dbed73cbSSangeeta Misra 		else
839dbed73cbSSangeeta Misra 			rc = ilbd_check_client_config_auth(ps);
840dbed73cbSSangeeta Misra 		/* generate the audit record before bailing out */
841dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
8421e6524b5SToomas Soome 			if (*rule_name != '\0') {
843dbed73cbSSangeeta Misra 				ilbd_audit_rule_event(rule_name, NULL,
844dbed73cbSSangeeta Misra 				    cmd, rc, ucredp);
845dbed73cbSSangeeta Misra 			} else {
846dbed73cbSSangeeta Misra 				(void) snprintf(rulename, sizeof (rulename),
847dbed73cbSSangeeta Misra 				    "all");
848dbed73cbSSangeeta Misra 				ilbd_audit_rule_event(rulename, NULL, cmd, rc,
849dbed73cbSSangeeta Misra 				    ucredp);
850dbed73cbSSangeeta Misra 			}
851dbed73cbSSangeeta Misra 			goto out;
852dbed73cbSSangeeta Misra 		}
853dbed73cbSSangeeta Misra 	}
854dbed73cbSSangeeta Misra 	is_all_rules = rule_name[0] == 0;
855dbed73cbSSangeeta Misra 
856dbed73cbSSangeeta Misra 	/* just one rule */
857dbed73cbSSangeeta Misra 	if (!is_all_rules) {
858dbed73cbSSangeeta Misra 		irl = i_find_rule_byname(rule_name);
859dbed73cbSSangeeta Misra 		if (irl == NULL) {
860dbed73cbSSangeeta Misra 			rc = ILB_STATUS_ENORULE;
861dbed73cbSSangeeta Misra 			ilbd_audit_rule_event(rule_name, NULL, cmd, rc, ucredp);
862dbed73cbSSangeeta Misra 			goto out;
863dbed73cbSSangeeta Misra 		}
864dbed73cbSSangeeta Misra 		/* auditing will be done by i_ilbd_action_switch() */
865dbed73cbSSangeeta Misra 		rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp);
866dbed73cbSSangeeta Misra 		goto out;
867dbed73cbSSangeeta Misra 	}
868dbed73cbSSangeeta Misra 
869dbed73cbSSangeeta Misra 	/* all rules: first tell the kernel, then walk the daemon's list */
870dbed73cbSSangeeta Misra 	kcmd.cmd = i_ilbd2ilb_cmd(cmd);
871dbed73cbSSangeeta Misra 	kcmd.flags = ILB_RULE_ALLRULES;
872dbed73cbSSangeeta Misra 
873dbed73cbSSangeeta Misra 	rc = do_ioctl(&kcmd, 0);
874dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK) {
875dbed73cbSSangeeta Misra 		(void) snprintf(rulename, sizeof (rulename), "all");
876dbed73cbSSangeeta Misra 		ilbd_audit_rule_event(rulename, NULL, cmd, rc, ucredp);
877dbed73cbSSangeeta Misra 		goto out;
878dbed73cbSSangeeta Misra 	}
879dbed73cbSSangeeta Misra 
880dbed73cbSSangeeta Misra 	irl = list_head(&ilbd_rule_hlist);
881dbed73cbSSangeeta Misra 	while (irl != NULL) {
882dbed73cbSSangeeta Misra 		irl_next = list_next(&ilbd_rule_hlist, irl);
883dbed73cbSSangeeta Misra 		irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES;
884dbed73cbSSangeeta Misra 		/* auditing will be done by i_ilbd_action_switch() */
885dbed73cbSSangeeta Misra 		rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp);
886dbed73cbSSangeeta Misra 		irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES;
887dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
888dbed73cbSSangeeta Misra 			goto rollback_list;
889dbed73cbSSangeeta Misra 		irl = irl_next;
890dbed73cbSSangeeta Misra 	}
891dbed73cbSSangeeta Misra 	return (rc);
892dbed73cbSSangeeta Misra 
893dbed73cbSSangeeta Misra rollback_list:
894dbed73cbSSangeeta Misra 	u_cmd = get_undo_cmd(cmd);
895dbed73cbSSangeeta Misra 	if (u_cmd == ILBD_BAD_CMD)
896dbed73cbSSangeeta Misra 		return (rc);
897dbed73cbSSangeeta Misra 
898dbed73cbSSangeeta Misra 	if (is_all_rules) {
899dbed73cbSSangeeta Misra 		kcmd.cmd = i_ilbd2ilb_cmd(u_cmd);
900dbed73cbSSangeeta Misra 		(void) do_ioctl(&kcmd, 0);
901dbed73cbSSangeeta Misra 	}
902dbed73cbSSangeeta Misra 	/* current list element failed, so we start with previous one */
903dbed73cbSSangeeta Misra 	irl = list_prev(&ilbd_rule_hlist, irl);
904dbed73cbSSangeeta Misra 	while (irl != NULL) {
905dbed73cbSSangeeta Misra 		if (is_all_rules)
906dbed73cbSSangeeta Misra 			irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES;
907dbed73cbSSangeeta Misra 
908dbed73cbSSangeeta Misra 		/*
909dbed73cbSSangeeta Misra 		 * When the processing of a command consists of
910dbed73cbSSangeeta Misra 		 * multiple sequential steps, and one of them fails,
911dbed73cbSSangeeta Misra 		 * ilbd performs rollback to undo the steps taken before the
912dbed73cbSSangeeta Misra 		 * failing step. Since ilbd is initiating these steps
913dbed73cbSSangeeta Misra 		 * there is not need to audit them.
914dbed73cbSSangeeta Misra 		 */
915dbed73cbSSangeeta Misra 		rc = i_ilbd_action_switch(irl, u_cmd, B_TRUE, NULL);
916dbed73cbSSangeeta Misra 		irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES;
917dbed73cbSSangeeta Misra 
918dbed73cbSSangeeta Misra 		irl = list_prev(&ilbd_rule_hlist, irl);
919dbed73cbSSangeeta Misra 	}
920dbed73cbSSangeeta Misra out:
921dbed73cbSSangeeta Misra 	return (rc);
922dbed73cbSSangeeta Misra }
923dbed73cbSSangeeta Misra 
924dbed73cbSSangeeta Misra ilb_status_t
ilbd_destroy_rule(ilbd_name_t rule_name,const struct passwd * ps,ucred_t * ucredp)925dbed73cbSSangeeta Misra ilbd_destroy_rule(ilbd_name_t rule_name, const struct passwd *ps,
926dbed73cbSSangeeta Misra     ucred_t *ucredp)
927dbed73cbSSangeeta Misra {
928dbed73cbSSangeeta Misra 	return (i_ilbd_rule_action(rule_name, ps, ILBD_DESTROY_RULE, ucredp));
929dbed73cbSSangeeta Misra }
930dbed73cbSSangeeta Misra 
931dbed73cbSSangeeta Misra ilb_status_t
ilbd_enable_rule(ilbd_name_t rule_name,const struct passwd * ps,ucred_t * ucredp)932dbed73cbSSangeeta Misra ilbd_enable_rule(ilbd_name_t rule_name, const struct passwd *ps,
933dbed73cbSSangeeta Misra     ucred_t *ucredp)
934dbed73cbSSangeeta Misra {
935dbed73cbSSangeeta Misra 	return (i_ilbd_rule_action(rule_name, ps, ILBD_ENABLE_RULE, ucredp));
936dbed73cbSSangeeta Misra 
937dbed73cbSSangeeta Misra }
938dbed73cbSSangeeta Misra 
939dbed73cbSSangeeta Misra ilb_status_t
ilbd_disable_rule(ilbd_name_t rule_name,const struct passwd * ps,ucred_t * ucredp)940dbed73cbSSangeeta Misra ilbd_disable_rule(ilbd_name_t rule_name, const struct passwd *ps,
941dbed73cbSSangeeta Misra     ucred_t *ucredp)
942dbed73cbSSangeeta Misra {
943dbed73cbSSangeeta Misra 	return (i_ilbd_rule_action(rule_name, ps, ILBD_DISABLE_RULE, ucredp));
944dbed73cbSSangeeta Misra }
945dbed73cbSSangeeta Misra 
946dbed73cbSSangeeta Misra /*
947dbed73cbSSangeeta Misra  * allocate storage for a kernel rule command and fill from
948dbed73cbSSangeeta Misra  * "template" irl, if non-NULL
949dbed73cbSSangeeta Misra  */
950dbed73cbSSangeeta Misra static ilb_rule_cmd_t *
i_alloc_kernel_rule_cmd(ilbd_rule_t * irl)951dbed73cbSSangeeta Misra i_alloc_kernel_rule_cmd(ilbd_rule_t *irl)
952dbed73cbSSangeeta Misra {
953dbed73cbSSangeeta Misra 	ilb_rule_cmd_t *kcmd;
954dbed73cbSSangeeta Misra 
955dbed73cbSSangeeta Misra 	kcmd = (ilb_rule_cmd_t *)malloc(sizeof (*kcmd));
956dbed73cbSSangeeta Misra 	if (kcmd == NULL)
957dbed73cbSSangeeta Misra 		return (kcmd);
958dbed73cbSSangeeta Misra 
959dbed73cbSSangeeta Misra 	bzero(kcmd, sizeof (*kcmd));
960dbed73cbSSangeeta Misra 
961dbed73cbSSangeeta Misra 	if (irl != NULL) {
962dbed73cbSSangeeta Misra 		kcmd->flags = irl->irl_flags;
963dbed73cbSSangeeta Misra 		kcmd->ip_ver = AF_2_IPPROTO(irl->irl_ipversion);
964dbed73cbSSangeeta Misra 		kcmd->vip = irl->irl_vip;
965dbed73cbSSangeeta Misra 		kcmd->proto = irl->irl_proto;
966dbed73cbSSangeeta Misra 		kcmd->min_port = irl->irl_minport;
967dbed73cbSSangeeta Misra 		kcmd->max_port = irl->irl_maxport;
968dbed73cbSSangeeta Misra 		kcmd->algo = algo_lib2impl(irl->irl_algo);
969dbed73cbSSangeeta Misra 		kcmd->topo = topo_lib2impl(irl->irl_topo);
970dbed73cbSSangeeta Misra 		kcmd->sticky_mask = irl->irl_stickymask;
971dbed73cbSSangeeta Misra 		kcmd->nat_src_start = irl->irl_nat_src_start;
972dbed73cbSSangeeta Misra 		kcmd->nat_src_end = irl->irl_nat_src_end;
973dbed73cbSSangeeta Misra 		kcmd->conn_drain_timeout = irl->irl_conndrain;
974dbed73cbSSangeeta Misra 		kcmd->nat_expiry = irl->irl_nat_timeout;
975dbed73cbSSangeeta Misra 		kcmd->sticky_expiry = irl->irl_sticky_timeout;
976dbed73cbSSangeeta Misra 		(void) strlcpy(kcmd->name, irl->irl_name,
977dbed73cbSSangeeta Misra 		    sizeof (kcmd->name));
978dbed73cbSSangeeta Misra 	}
979dbed73cbSSangeeta Misra 	return (kcmd);
980dbed73cbSSangeeta Misra }
981dbed73cbSSangeeta Misra 
982dbed73cbSSangeeta Misra /*
983dbed73cbSSangeeta Misra  * ncount is the next to be used index into (*kcmdp)->servers
984dbed73cbSSangeeta Misra  */
985dbed73cbSSangeeta Misra static ilb_status_t
adjust_srv_info_cmd(ilb_servers_info_cmd_t ** kcmdp,int index)986dbed73cbSSangeeta Misra adjust_srv_info_cmd(ilb_servers_info_cmd_t **kcmdp, int index)
987dbed73cbSSangeeta Misra {
988dbed73cbSSangeeta Misra 	ilb_servers_info_cmd_t	*kcmd = *kcmdp;
989dbed73cbSSangeeta Misra 	size_t			sz;
990dbed73cbSSangeeta Misra 
991dbed73cbSSangeeta Misra 	if (kcmd != NULL && kcmd->num_servers > index + 1)
992dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
993dbed73cbSSangeeta Misra 
994dbed73cbSSangeeta Misra 	/*
995dbed73cbSSangeeta Misra 	 * the first ilb_server_info_t is part of *kcmd, so
996dbed73cbSSangeeta Misra 	 * by using index (which is one less than the total needed) here,
997dbed73cbSSangeeta Misra 	 * we allocate exactly the amount we need.
998dbed73cbSSangeeta Misra 	 */
999dbed73cbSSangeeta Misra 	sz = sizeof (*kcmd) + (index * sizeof (ilb_server_info_t));
1000dbed73cbSSangeeta Misra 	kcmd = (ilb_servers_info_cmd_t *)realloc(kcmd, sz);
1001dbed73cbSSangeeta Misra 	if (kcmd == NULL)
1002dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
1003dbed73cbSSangeeta Misra 
1004dbed73cbSSangeeta Misra 	/*
1005dbed73cbSSangeeta Misra 	 * we don't count the slot we newly allocated yet.
1006dbed73cbSSangeeta Misra 	 */
1007dbed73cbSSangeeta Misra 	kcmd->num_servers = index;
1008dbed73cbSSangeeta Misra 	*kcmdp = kcmd;
1009dbed73cbSSangeeta Misra 
1010dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
1011dbed73cbSSangeeta Misra }
1012dbed73cbSSangeeta Misra 
1013dbed73cbSSangeeta Misra /*
1014dbed73cbSSangeeta Misra  * this function adds all servers in srvlist to the kernel(!) rule
1015dbed73cbSSangeeta Misra  * the name of which is passed as argument.
1016dbed73cbSSangeeta Misra  */
1017dbed73cbSSangeeta Misra static ilb_status_t
i_update_ksrv_rules(char * name,ilbd_sg_t * sg,ilbd_rule_t * rl)1018dbed73cbSSangeeta Misra i_update_ksrv_rules(char *name, ilbd_sg_t *sg, ilbd_rule_t *rl)
1019dbed73cbSSangeeta Misra {
1020dbed73cbSSangeeta Misra 	ilb_status_t		rc;
1021dbed73cbSSangeeta Misra 	ilbd_srv_t		*srvp;
1022dbed73cbSSangeeta Misra 	ilb_servers_info_cmd_t	*kcmd = NULL;
1023dbed73cbSSangeeta Misra 	int			i;
1024dbed73cbSSangeeta Misra 
1025dbed73cbSSangeeta Misra 	/*
1026dbed73cbSSangeeta Misra 	 * If the servergroup doesn't have any servers associated with
1027dbed73cbSSangeeta Misra 	 * it yet, there's nothing more to do here.
1028dbed73cbSSangeeta Misra 	 */
1029dbed73cbSSangeeta Misra 	if (sg->isg_srvcount == 0)
1030dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
1031dbed73cbSSangeeta Misra 
1032dbed73cbSSangeeta Misra 	/*
1033dbed73cbSSangeeta Misra 	 * walk the list of servers attached to this SG
1034dbed73cbSSangeeta Misra 	 */
1035dbed73cbSSangeeta Misra 	srvp = list_head(&sg->isg_srvlist);
1036dbed73cbSSangeeta Misra 	for (i = 0; srvp != NULL; srvp = list_next(&sg->isg_srvlist, srvp)) {
1037dbed73cbSSangeeta Misra 		rc = adjust_srv_info_cmd(&kcmd, i);
1038dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
103956b8f71eSSerghei Samsi 			goto rollback_kcmd;
1040dbed73cbSSangeeta Misra 
1041dbed73cbSSangeeta Misra 		ILB_SGSRV_2_KSRV(&srvp->isv_srv, &kcmd->servers[i]);
1042dbed73cbSSangeeta Misra 		/*
1043dbed73cbSSangeeta Misra 		 * "no port" means "copy rule's port" (for kernel rule)
1044dbed73cbSSangeeta Misra 		 */
1045dbed73cbSSangeeta Misra 		if (kcmd->servers[i].min_port == 0) {
1046dbed73cbSSangeeta Misra 			kcmd->servers[i].min_port = rl->irl_minport;
1047dbed73cbSSangeeta Misra 			kcmd->servers[i].max_port = rl->irl_maxport;
1048dbed73cbSSangeeta Misra 		}
1049dbed73cbSSangeeta Misra 		i++;
1050dbed73cbSSangeeta Misra 	}
105156b8f71eSSerghei Samsi 	assert(kcmd != NULL);
1052dbed73cbSSangeeta Misra 
1053dbed73cbSSangeeta Misra 	kcmd->cmd = ILB_ADD_SERVERS;
1054dbed73cbSSangeeta Misra 	kcmd->num_servers = i;
1055dbed73cbSSangeeta Misra 	(void) strlcpy(kcmd->name, name, sizeof (kcmd->name));
1056dbed73cbSSangeeta Misra 
1057dbed73cbSSangeeta Misra 	rc = do_ioctl(kcmd, 0);
1058dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK)
105956b8f71eSSerghei Samsi 		goto rollback_kcmd;
1060dbed73cbSSangeeta Misra 
1061dbed73cbSSangeeta Misra 	for (i = 0; i < kcmd->num_servers; i++) {
1062dbed73cbSSangeeta Misra 		int e;
1063dbed73cbSSangeeta Misra 
1064dbed73cbSSangeeta Misra 		if ((e = kcmd->servers[i].err) != 0) {
1065dbed73cbSSangeeta Misra 			logerr("i_update_ksrv_rules "
1066dbed73cbSSangeeta Misra 			    "ioctl indicates failure: %s", strerror(e));
1067dbed73cbSSangeeta Misra 			rc = ilb_map_errno2ilbstat(e);
1068dbed73cbSSangeeta Misra 			/*
1069dbed73cbSSangeeta Misra 			 * if adding even a single server failed, we need to
1070dbed73cbSSangeeta Misra 			 * roll back the whole wad. We ignore any errors and
1071dbed73cbSSangeeta Misra 			 * return the one that was returned by the first ioctl.
1072dbed73cbSSangeeta Misra 			 */
1073dbed73cbSSangeeta Misra 			kcmd->cmd = ILB_DEL_SERVERS;
1074dbed73cbSSangeeta Misra 			(void) do_ioctl(kcmd, 0);
107556b8f71eSSerghei Samsi 			goto rollback_kcmd;
1076dbed73cbSSangeeta Misra 		}
1077dbed73cbSSangeeta Misra 	}
1078dbed73cbSSangeeta Misra 
107956b8f71eSSerghei Samsi rollback_kcmd:
108056b8f71eSSerghei Samsi 	free(kcmd);
108156b8f71eSSerghei Samsi 	return (rc);
1082dbed73cbSSangeeta Misra }
1083dbed73cbSSangeeta Misra 
1084dbed73cbSSangeeta Misra /* convert a struct in6_addr to valstr */
1085dbed73cbSSangeeta Misra void
ilbd_ip_to_str(uint16_t ipversion,struct in6_addr * addr,char * valstr)1086dbed73cbSSangeeta Misra ilbd_ip_to_str(uint16_t ipversion, struct in6_addr *addr, char *valstr)
1087dbed73cbSSangeeta Misra {
1088dbed73cbSSangeeta Misra 	size_t	vallen;
1089dbed73cbSSangeeta Misra 	ilb_ip_addr_t	ipaddr;
1090dbed73cbSSangeeta Misra 	void	*addrptr;
1091dbed73cbSSangeeta Misra 
1092dbed73cbSSangeeta Misra 	vallen = (ipversion == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1093dbed73cbSSangeeta Misra 
1094dbed73cbSSangeeta Misra 	IP_COPY_IMPL_2_CLI(addr, &ipaddr);
1095dbed73cbSSangeeta Misra 	addrptr = (ipversion == AF_INET) ?
1096dbed73cbSSangeeta Misra 	    (void *)&ipaddr.ia_v4 : (void *)&ipaddr.ia_v6;
109795c74518SToomas Soome 	if (inet_ntop(ipversion, (void *)addrptr, valstr, vallen) == NULL)
1098dbed73cbSSangeeta Misra 		logerr("ilbd_ip_to_str: inet_ntop failed");
1099dbed73cbSSangeeta Misra 	return;
1100dbed73cbSSangeeta Misra 
1101dbed73cbSSangeeta Misra }
1102dbed73cbSSangeeta Misra 
1103dbed73cbSSangeeta Misra ilb_status_t
ilbd_create_rule(ilb_rule_info_t * rl,int ev_port,const struct passwd * ps,ucred_t * ucredp)1104dbed73cbSSangeeta Misra ilbd_create_rule(ilb_rule_info_t *rl, int ev_port,
1105dbed73cbSSangeeta Misra     const struct passwd *ps, ucred_t *ucredp)
1106dbed73cbSSangeeta Misra {
1107dbed73cbSSangeeta Misra 	ilb_status_t	rc;
1108dbed73cbSSangeeta Misra 	ilbd_rule_t	*irl = NULL;
1109dbed73cbSSangeeta Misra 	ilbd_sg_t	*sg;
1110dbed73cbSSangeeta Misra 	ilb_rule_cmd_t	*kcmd = NULL;
1111dbed73cbSSangeeta Misra 
1112dbed73cbSSangeeta Misra 	if (ps != NULL) {
1113dbed73cbSSangeeta Misra 		if ((rc = ilbd_check_client_config_auth(ps)) != ILB_STATUS_OK)
1114dbed73cbSSangeeta Misra 			goto out;
1115dbed73cbSSangeeta Misra 	}
1116dbed73cbSSangeeta Misra 
1117dbed73cbSSangeeta Misra 	if (i_find_rule_byname(rl->rl_name) != NULL) {
1118dbed73cbSSangeeta Misra 		logdebug("ilbd_create_rule: rule %s"
1119dbed73cbSSangeeta Misra 		    " already exists", rl->rl_name);
1120dbed73cbSSangeeta Misra 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
1121dbed73cbSSangeeta Misra 		    ILB_STATUS_DUP_RULE, ucredp);
1122dbed73cbSSangeeta Misra 		return (ILB_STATUS_DUP_RULE);
1123dbed73cbSSangeeta Misra 	}
1124dbed73cbSSangeeta Misra 
1125dbed73cbSSangeeta Misra 	sg = i_find_sg_byname(rl->rl_sgname);
1126dbed73cbSSangeeta Misra 	if (sg == NULL) {
1127dbed73cbSSangeeta Misra 		logdebug("ilbd_create_rule: rule %s uses non-existent"
1128dbed73cbSSangeeta Misra 		    " servergroup name %s", rl->rl_name, rl->rl_sgname);
1129dbed73cbSSangeeta Misra 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
1130dbed73cbSSangeeta Misra 		    ILB_STATUS_SGUNAVAIL, ucredp);
1131dbed73cbSSangeeta Misra 		return (ILB_STATUS_SGUNAVAIL);
1132dbed73cbSSangeeta Misra 	}
1133dbed73cbSSangeeta Misra 
1134dbed73cbSSangeeta Misra 	if ((rc = ilbd_sg_check_rule_port(sg, rl)) != ILB_STATUS_OK) {
1135dbed73cbSSangeeta Misra 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp);
1136dbed73cbSSangeeta Misra 		return (rc);
1137dbed73cbSSangeeta Misra 	}
1138dbed73cbSSangeeta Misra 
1139dbed73cbSSangeeta Misra 	/* allocs and copies contents of arg (if != NULL) into new rule */
1140dbed73cbSSangeeta Misra 	irl = i_alloc_ilbd_rule(rl);
1141dbed73cbSSangeeta Misra 	if (irl == NULL) {
1142dbed73cbSSangeeta Misra 		ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
1143dbed73cbSSangeeta Misra 		    ILB_STATUS_ENOMEM, ucredp);
1144dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
1145dbed73cbSSangeeta Misra 	}
1146dbed73cbSSangeeta Misra 
1147dbed73cbSSangeeta Misra 	/* make sure rule's IPversion (via vip) and SG's match */
1148dbed73cbSSangeeta Misra 	if (sg->isg_srvcount > 0) {
1149dbed73cbSSangeeta Misra 		ilbd_srv_t	*srv = list_head(&sg->isg_srvlist);
1150dbed73cbSSangeeta Misra 		int32_t		r_af = rl->rl_ipversion;
1151dbed73cbSSangeeta Misra 		int32_t		s_af = GET_AF(&srv->isv_addr);
1152dbed73cbSSangeeta Misra 
1153dbed73cbSSangeeta Misra 		if (r_af != s_af) {
1154dbed73cbSSangeeta Misra 			logdebug("address family mismatch with servergroup");
1155dbed73cbSSangeeta Misra 			rc = ILB_STATUS_MISMATCHSG;
1156dbed73cbSSangeeta Misra 			goto out;
1157dbed73cbSSangeeta Misra 		}
1158dbed73cbSSangeeta Misra 	}
1159dbed73cbSSangeeta Misra 	irl->irl_sg = sg;
1160dbed73cbSSangeeta Misra 
1161dbed73cbSSangeeta Misra 	/* Try associating the rule with the given hc oject. */
1162dbed73cbSSangeeta Misra 	if (RULE_HAS_HC(irl)) {
1163dbed73cbSSangeeta Misra 		if ((rc = ilbd_hc_associate_rule(irl, ev_port)) !=
1164dbed73cbSSangeeta Misra 		    ILB_STATUS_OK)
1165dbed73cbSSangeeta Misra 			goto out;
1166dbed73cbSSangeeta Misra 	}
1167dbed73cbSSangeeta Misra 
1168dbed73cbSSangeeta Misra 	/*
1169dbed73cbSSangeeta Misra 	 * checks are done, now:
1170dbed73cbSSangeeta Misra 	 * 1. create rule in kernel
1171dbed73cbSSangeeta Misra 	 * 2. tell it about the backend server (which we maintain in SG)
1172dbed73cbSSangeeta Misra 	 * 3. attach the rule in memory
1173dbed73cbSSangeeta Misra 	 */
1174dbed73cbSSangeeta Misra 	/* 1. */
1175dbed73cbSSangeeta Misra 	/* allocs and copies contents of arg (if != NULL) into new rule */
1176dbed73cbSSangeeta Misra 	kcmd = i_alloc_kernel_rule_cmd(irl);
1177dbed73cbSSangeeta Misra 	if (kcmd == NULL) {
1178dbed73cbSSangeeta Misra 		rc = ILB_STATUS_ENOMEM;
1179dbed73cbSSangeeta Misra 		goto rollback_hc;
1180dbed73cbSSangeeta Misra 	}
1181dbed73cbSSangeeta Misra 	kcmd->cmd = ILB_CREATE_RULE;
1182dbed73cbSSangeeta Misra 
1183dbed73cbSSangeeta Misra 	rc = do_ioctl(kcmd, 0);
1184dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK)
1185dbed73cbSSangeeta Misra 		goto rollback_kcmd;
1186dbed73cbSSangeeta Misra 
1187dbed73cbSSangeeta Misra 	/* 2. */
1188dbed73cbSSangeeta Misra 	rc = i_update_ksrv_rules(kcmd->name, sg, irl);
1189dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK)
1190dbed73cbSSangeeta Misra 		goto rollback_kcmd;
1191dbed73cbSSangeeta Misra 
1192dbed73cbSSangeeta Misra 	/* 3. */
1193dbed73cbSSangeeta Misra 	(void) i_attach_rule2sg(sg, irl);
1194dbed73cbSSangeeta Misra 	list_insert_tail(&ilbd_rule_hlist, irl);
1195dbed73cbSSangeeta Misra 
1196dbed73cbSSangeeta Misra 	if (ps != NULL) {
1197dbed73cbSSangeeta Misra 		rc = i_ilbd_save_rule(irl, ILBD_SCF_CREATE);
1198dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK)
1199dbed73cbSSangeeta Misra 			goto rollback_rule;
1200dbed73cbSSangeeta Misra 	}
1201dbed73cbSSangeeta Misra 
1202dbed73cbSSangeeta Misra 	free(kcmd);
1203dbed73cbSSangeeta Misra 	ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE,
1204dbed73cbSSangeeta Misra 	    ILB_STATUS_OK, ucredp);
1205dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
1206dbed73cbSSangeeta Misra 
1207dbed73cbSSangeeta Misra rollback_rule:
1208dbed73cbSSangeeta Misra 	/*
1209dbed73cbSSangeeta Misra 	 * ilbd_destroy_one_rule() also frees irl, as well as dissociate
1210dbed73cbSSangeeta Misra 	 * rule and HC, so all we need to do afterwards is free the kcmd
1211dbed73cbSSangeeta Misra 	 * and return.
1212dbed73cbSSangeeta Misra 	 */
1213dbed73cbSSangeeta Misra 	(void) ilbd_destroy_one_rule(irl);
1214dbed73cbSSangeeta Misra 	ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp);
1215dbed73cbSSangeeta Misra 	free(kcmd);
1216dbed73cbSSangeeta Misra 	return (rc);
1217dbed73cbSSangeeta Misra 
1218dbed73cbSSangeeta Misra rollback_kcmd:
1219dbed73cbSSangeeta Misra 	free(kcmd);
1220dbed73cbSSangeeta Misra rollback_hc:
1221dbed73cbSSangeeta Misra 	/* Cannot fail since the rule is just associated with the hc object. */
1222dbed73cbSSangeeta Misra 	if (RULE_HAS_HC(irl))
1223dbed73cbSSangeeta Misra 		(void) ilbd_hc_dissociate_rule(irl);
1224dbed73cbSSangeeta Misra out:
1225dbed73cbSSangeeta Misra 	ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp);
1226dbed73cbSSangeeta Misra 	free(irl);
1227dbed73cbSSangeeta Misra 	return (rc);
1228dbed73cbSSangeeta Misra }
1229dbed73cbSSangeeta Misra 
1230dbed73cbSSangeeta Misra static uint32_t
i_flags_d2k(int f)1231dbed73cbSSangeeta Misra i_flags_d2k(int f)
1232dbed73cbSSangeeta Misra {
1233dbed73cbSSangeeta Misra 	uint32_t	r = 0;
1234dbed73cbSSangeeta Misra 
1235dbed73cbSSangeeta Misra 	if (ILB_IS_SRV_ENABLED(f))
1236dbed73cbSSangeeta Misra 		r |= ILB_SERVER_ENABLED;
1237dbed73cbSSangeeta Misra 	/* more as they are defined */
1238dbed73cbSSangeeta Misra 
1239dbed73cbSSangeeta Misra 	return (r);
1240dbed73cbSSangeeta Misra }
1241dbed73cbSSangeeta Misra 
1242dbed73cbSSangeeta Misra /*
1243dbed73cbSSangeeta Misra  * walk the list of rules and add srv to the *kernel* rule
1244dbed73cbSSangeeta Misra  * (this is a list of rules hanging off of a server group)
1245dbed73cbSSangeeta Misra  */
1246dbed73cbSSangeeta Misra ilb_status_t
i_add_srv2krules(list_t * rlist,ilb_sg_srv_t * srv,int ev_port)1247dbed73cbSSangeeta Misra i_add_srv2krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port)
1248dbed73cbSSangeeta Misra {
1249dbed73cbSSangeeta Misra 	ilb_status_t		rc = ILB_STATUS_OK;
1250dbed73cbSSangeeta Misra 	ilbd_rule_t		*rl, *del_rl;
1251dbed73cbSSangeeta Misra 	ilb_servers_info_cmd_t	kcmd;
1252dbed73cbSSangeeta Misra 	ilb_servers_cmd_t	del_kcmd;
1253dbed73cbSSangeeta Misra 
1254dbed73cbSSangeeta Misra 	kcmd.cmd = ILB_ADD_SERVERS;
1255dbed73cbSSangeeta Misra 	kcmd.num_servers = 1;
1256dbed73cbSSangeeta Misra 	kcmd.servers[0].err = 0;
1257dbed73cbSSangeeta Misra 	kcmd.servers[0].addr = srv->sgs_addr;
1258dbed73cbSSangeeta Misra 	kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags);
1259dbed73cbSSangeeta Misra 	(void) strlcpy(kcmd.servers[0].name, srv->sgs_srvID,
1260dbed73cbSSangeeta Misra 	    sizeof (kcmd.servers[0].name));
1261dbed73cbSSangeeta Misra 
1262dbed73cbSSangeeta Misra 	/*
1263dbed73cbSSangeeta Misra 	 * a note about rollback: since we need to start rollback with the
1264dbed73cbSSangeeta Misra 	 * current list element in some case, and with the previous one
1265dbed73cbSSangeeta Misra 	 * in others, we must "go back" in this latter case before
1266dbed73cbSSangeeta Misra 	 * we jump to the rollback code.
1267dbed73cbSSangeeta Misra 	 */
1268dbed73cbSSangeeta Misra 	for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) {
1269dbed73cbSSangeeta Misra 		(void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name));
1270dbed73cbSSangeeta Misra 		/*
1271dbed73cbSSangeeta Misra 		 * sgs_minport == 0 means "no port specified"; this
1272dbed73cbSSangeeta Misra 		 * indicates that the server matches anything the rule
1273dbed73cbSSangeeta Misra 		 * provides.
1274dbed73cbSSangeeta Misra 		 * NOTE: this can be different for different rules
1275dbed73cbSSangeeta Misra 		 * using the same server group, therefore we don't modify
1276dbed73cbSSangeeta Misra 		 * this information in the servergroup, but *only* in
1277dbed73cbSSangeeta Misra 		 * the kernel's rule.
1278dbed73cbSSangeeta Misra 		 */
1279dbed73cbSSangeeta Misra 		if (srv->sgs_minport == 0) {
1280dbed73cbSSangeeta Misra 			kcmd.servers[0].min_port = rl->irl_minport;
1281dbed73cbSSangeeta Misra 			kcmd.servers[0].max_port = rl->irl_maxport;
1282dbed73cbSSangeeta Misra 		} else {
1283dbed73cbSSangeeta Misra 			kcmd.servers[0].min_port = srv->sgs_minport;
1284dbed73cbSSangeeta Misra 			kcmd.servers[0].max_port = srv->sgs_maxport;
1285dbed73cbSSangeeta Misra 		}
1286dbed73cbSSangeeta Misra 		rc = do_ioctl((void *)&kcmd, 0);
1287dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
1288dbed73cbSSangeeta Misra 			logdebug("i_add_srv2krules: do_ioctl call failed");
1289dbed73cbSSangeeta Misra 			del_rl = list_prev(rlist, rl);
1290dbed73cbSSangeeta Misra 			goto rollback;
1291dbed73cbSSangeeta Misra 		}
1292dbed73cbSSangeeta Misra 
1293dbed73cbSSangeeta Misra 		/*
1294dbed73cbSSangeeta Misra 		 * if ioctl() returns != 0, it doesn't perform the copyout
1295dbed73cbSSangeeta Misra 		 * necessary to indicate *which* server failed (we could be
1296dbed73cbSSangeeta Misra 		 * adding more than one); therefore we must check this
1297dbed73cbSSangeeta Misra 		 * 'err' field even if ioctl() returns 0.
1298dbed73cbSSangeeta Misra 		 */
1299dbed73cbSSangeeta Misra 		if (kcmd.servers[0].err != 0) {
1300dbed73cbSSangeeta Misra 			logerr("i_add_srv2krules: SIOCILB ioctl returned"
1301dbed73cbSSangeeta Misra 			    " error %d", kcmd.servers[0].err);
1302dbed73cbSSangeeta Misra 			rc = ilb_map_errno2ilbstat(kcmd.servers[0].err);
1303dbed73cbSSangeeta Misra 			del_rl = list_prev(rlist, rl);
1304dbed73cbSSangeeta Misra 			goto rollback;
1305dbed73cbSSangeeta Misra 		}
1306dbed73cbSSangeeta Misra 		if (RULE_HAS_HC(rl)) {
1307dbed73cbSSangeeta Misra 			if ((rc = ilbd_hc_add_server(rl, srv, ev_port)) !=
1308dbed73cbSSangeeta Misra 			    ILB_STATUS_OK) {
1309dbed73cbSSangeeta Misra 				logerr("i_add_srv2krules: cannot start timer "
1310dbed73cbSSangeeta Misra 				    " for rules %s server %s", rl->irl_name,
1311dbed73cbSSangeeta Misra 				    srv->sgs_srvID);
1312dbed73cbSSangeeta Misra 
1313dbed73cbSSangeeta Misra 				del_rl = rl;
1314dbed73cbSSangeeta Misra 				goto rollback;
1315dbed73cbSSangeeta Misra 			}
1316dbed73cbSSangeeta Misra 		}
1317dbed73cbSSangeeta Misra 	}
1318dbed73cbSSangeeta Misra 
1319dbed73cbSSangeeta Misra 	return (rc);
1320dbed73cbSSangeeta Misra 
1321dbed73cbSSangeeta Misra rollback:
1322dbed73cbSSangeeta Misra 	/*
1323dbed73cbSSangeeta Misra 	 * this is almost, but not quite, the same as i_rem_srv_frm_krules()
1324dbed73cbSSangeeta Misra 	 * therefore we keep it seperate.
1325dbed73cbSSangeeta Misra 	 */
1326dbed73cbSSangeeta Misra 	del_kcmd.cmd = ILB_DEL_SERVERS;
1327dbed73cbSSangeeta Misra 	del_kcmd.num_servers = 1;
1328dbed73cbSSangeeta Misra 	del_kcmd.servers[0].addr = srv->sgs_addr;
1329dbed73cbSSangeeta Misra 	while (del_rl != NULL) {
1330dbed73cbSSangeeta Misra 		if (RULE_HAS_HC(del_rl))
1331dbed73cbSSangeeta Misra 			(void) ilbd_hc_del_server(del_rl, srv);
1332dbed73cbSSangeeta Misra 		(void) strlcpy(del_kcmd.name, del_rl->irl_name,
1333dbed73cbSSangeeta Misra 		    sizeof (del_kcmd.name));
1334dbed73cbSSangeeta Misra 		(void) do_ioctl((void *)&del_kcmd, 0);
1335dbed73cbSSangeeta Misra 		del_rl = list_prev(rlist, del_rl);
1336dbed73cbSSangeeta Misra 	}
1337dbed73cbSSangeeta Misra 
1338dbed73cbSSangeeta Misra 	return (rc);
1339dbed73cbSSangeeta Misra }
1340dbed73cbSSangeeta Misra 
1341dbed73cbSSangeeta Misra /*
1342dbed73cbSSangeeta Misra  * ev_port is only used for rollback purposes in this function
1343dbed73cbSSangeeta Misra  */
1344dbed73cbSSangeeta Misra ilb_status_t
i_rem_srv_frm_krules(list_t * rlist,ilb_sg_srv_t * srv,int ev_port)1345dbed73cbSSangeeta Misra i_rem_srv_frm_krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port)
1346dbed73cbSSangeeta Misra {
1347dbed73cbSSangeeta Misra 	ilb_status_t		rc = ILB_STATUS_OK;
1348dbed73cbSSangeeta Misra 	ilbd_rule_t		*rl, *add_rl;
1349dbed73cbSSangeeta Misra 	ilb_servers_cmd_t	kcmd;
1350dbed73cbSSangeeta Misra 	ilb_servers_info_cmd_t	add_kcmd;
1351dbed73cbSSangeeta Misra 
1352dbed73cbSSangeeta Misra 	kcmd.cmd = ILB_DEL_SERVERS;
1353dbed73cbSSangeeta Misra 	kcmd.num_servers = 1;
1354dbed73cbSSangeeta Misra 	kcmd.servers[0].err = 0;
1355dbed73cbSSangeeta Misra 	kcmd.servers[0].addr = srv->sgs_addr;
1356dbed73cbSSangeeta Misra 
1357dbed73cbSSangeeta Misra 	for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) {
1358dbed73cbSSangeeta Misra 		(void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name));
1359dbed73cbSSangeeta Misra 		rc = do_ioctl((void *)&kcmd, 0);
1360dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
1361dbed73cbSSangeeta Misra 			logdebug("i_rem_srv_frm_krules: do_ioctl"
1362dbed73cbSSangeeta Misra 			    "call failed");
1363dbed73cbSSangeeta Misra 			add_rl = list_prev(rlist, rl);
1364dbed73cbSSangeeta Misra 			goto rollback;
1365dbed73cbSSangeeta Misra 		}
1366dbed73cbSSangeeta Misra 		/*
1367dbed73cbSSangeeta Misra 		 * if ioctl() returns != 0, it doesn't perform the copyout
1368dbed73cbSSangeeta Misra 		 * necessary to indicate *which* server failed (we could be
1369dbed73cbSSangeeta Misra 		 * removing more than one); therefore we must check this
1370dbed73cbSSangeeta Misra 		 * 'err' field even if ioctl() returns 0.
1371dbed73cbSSangeeta Misra 		 */
1372dbed73cbSSangeeta Misra 		if (kcmd.servers[0].err != 0) {
1373dbed73cbSSangeeta Misra 			logerr("i_rem_srv_frm_krules: SIOCILB ioctl"
1374dbed73cbSSangeeta Misra 			    " returned error %s",
1375dbed73cbSSangeeta Misra 			    strerror(kcmd.servers[0].err));
1376dbed73cbSSangeeta Misra 			rc = ilb_map_errno2ilbstat(kcmd.servers[0].err);
1377dbed73cbSSangeeta Misra 			add_rl = list_prev(rlist, rl);
1378dbed73cbSSangeeta Misra 			goto rollback;
1379dbed73cbSSangeeta Misra 		}
1380dbed73cbSSangeeta Misra 		if (RULE_HAS_HC(rl) &&
1381dbed73cbSSangeeta Misra 		    (rc = ilbd_hc_del_server(rl, srv)) != ILB_STATUS_OK) {
1382dbed73cbSSangeeta Misra 			logerr("i_rem_srv_frm_krules: cannot delete "
1383dbed73cbSSangeeta Misra 			    "timer for rules %s server %s", rl->irl_name,
1384dbed73cbSSangeeta Misra 			    srv->sgs_srvID);
1385dbed73cbSSangeeta Misra 			add_rl = rl;
1386dbed73cbSSangeeta Misra 			goto rollback;
1387dbed73cbSSangeeta Misra 		}
1388dbed73cbSSangeeta Misra 	}
1389dbed73cbSSangeeta Misra 
1390dbed73cbSSangeeta Misra 	return (rc);
1391dbed73cbSSangeeta Misra 
1392dbed73cbSSangeeta Misra rollback:
1393dbed73cbSSangeeta Misra 	/* Don't do roll back if ev_port == -1. */
1394dbed73cbSSangeeta Misra 	if (ev_port == -1)
1395dbed73cbSSangeeta Misra 		return (rc);
1396dbed73cbSSangeeta Misra 
1397dbed73cbSSangeeta Misra 	add_kcmd.cmd = ILB_ADD_SERVERS;
1398dbed73cbSSangeeta Misra 	add_kcmd.num_servers = 1;
1399dbed73cbSSangeeta Misra 	add_kcmd.servers[0].err = 0;
1400dbed73cbSSangeeta Misra 	add_kcmd.servers[0].addr = srv->sgs_addr;
1401dbed73cbSSangeeta Misra 	add_kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags);
1402dbed73cbSSangeeta Misra 	(void) strlcpy(add_kcmd.servers[0].name, srv->sgs_srvID,
1403dbed73cbSSangeeta Misra 	    sizeof (add_kcmd.servers[0].name));
1404dbed73cbSSangeeta Misra 	while (add_rl != NULL) {
1405dbed73cbSSangeeta Misra 		if (srv->sgs_minport == 0) {
1406dbed73cbSSangeeta Misra 			add_kcmd.servers[0].min_port = add_rl->irl_minport;
1407dbed73cbSSangeeta Misra 			add_kcmd.servers[0].max_port = add_rl->irl_maxport;
1408dbed73cbSSangeeta Misra 		} else {
1409dbed73cbSSangeeta Misra 			add_kcmd.servers[0].min_port = srv->sgs_minport;
1410dbed73cbSSangeeta Misra 			add_kcmd.servers[0].max_port = srv->sgs_maxport;
1411dbed73cbSSangeeta Misra 		}
1412dbed73cbSSangeeta Misra 		if (RULE_HAS_HC(add_rl))
1413dbed73cbSSangeeta Misra 			(void) ilbd_hc_add_server(add_rl, srv, ev_port);
1414dbed73cbSSangeeta Misra 		(void) strlcpy(add_kcmd.name, add_rl->irl_name,
1415dbed73cbSSangeeta Misra 		    sizeof (add_kcmd.name));
1416dbed73cbSSangeeta Misra 		(void) do_ioctl((void *)&add_kcmd, 0);
1417dbed73cbSSangeeta Misra 		add_rl = list_prev(rlist, add_rl);
1418dbed73cbSSangeeta Misra 	}
1419dbed73cbSSangeeta Misra 
1420dbed73cbSSangeeta Misra 	return (rc);
1421dbed73cbSSangeeta Misra }
1422