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.
24*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
25dbed73cbSSangeeta Misra  */
26dbed73cbSSangeeta Misra 
27dbed73cbSSangeeta Misra #include <stdlib.h>
28dbed73cbSSangeeta Misra #include <strings.h>
29dbed73cbSSangeeta Misra #include <stddef.h>
30dbed73cbSSangeeta Misra #include <sys/types.h>
31dbed73cbSSangeeta Misra #include <sys/socket.h>
32dbed73cbSSangeeta Misra #include <sys/list.h>
33dbed73cbSSangeeta Misra #include <assert.h>
34dbed73cbSSangeeta Misra #include <errno.h>
35dbed73cbSSangeeta Misra #include <libilb.h>
36dbed73cbSSangeeta Misra #include <net/if.h>
37dbed73cbSSangeeta Misra #include <inet/ilb.h>
38dbed73cbSSangeeta Misra #include <netinet/in.h>
39dbed73cbSSangeeta Misra #include <arpa/inet.h>
40dbed73cbSSangeeta Misra #include "libilb_impl.h"
41dbed73cbSSangeeta Misra #include "ilbd.h"
42dbed73cbSSangeeta Misra 
43dbed73cbSSangeeta Misra typedef enum {
44dbed73cbSSangeeta Misra 	not_searched,
45dbed73cbSSangeeta Misra 	stop_found,
46dbed73cbSSangeeta Misra 	cont_search,
47dbed73cbSSangeeta Misra 	fail_search
48dbed73cbSSangeeta Misra } srch_ind_t;
49dbed73cbSSangeeta Misra 
50dbed73cbSSangeeta Misra static list_t	ilbd_sg_hlist;
51dbed73cbSSangeeta Misra 
52dbed73cbSSangeeta Misra static ilb_status_t i_delete_srv(ilbd_sg_t *, ilbd_srv_t *, int);
53dbed73cbSSangeeta Misra static void i_ilbd_free_srvID(ilbd_sg_t *, int32_t);
54dbed73cbSSangeeta Misra 
55dbed73cbSSangeeta Misra /* Last parameter to pass to i_find_srv(), specifying the matching mode */
56dbed73cbSSangeeta Misra #define	MODE_ADDR	1
57dbed73cbSSangeeta Misra #define	MODE_SRVID	2
58dbed73cbSSangeeta Misra 
59dbed73cbSSangeeta Misra static ilbd_srv_t *i_find_srv(list_t *, ilb_sg_srv_t *, int);
60dbed73cbSSangeeta Misra 
61dbed73cbSSangeeta Misra void
i_setup_sg_hlist(void)62dbed73cbSSangeeta Misra i_setup_sg_hlist(void)
63dbed73cbSSangeeta Misra {
64dbed73cbSSangeeta Misra 	list_create(&ilbd_sg_hlist, sizeof (ilbd_sg_t),
65dbed73cbSSangeeta Misra 	    offsetof(ilbd_sg_t, isg_link));
66dbed73cbSSangeeta Misra }
67dbed73cbSSangeeta Misra 
68dbed73cbSSangeeta Misra /*
69dbed73cbSSangeeta Misra  * allocate storage for a daemon-internal server group, init counters
70dbed73cbSSangeeta Misra  */
71dbed73cbSSangeeta Misra static ilbd_sg_t *
i_ilbd_alloc_sg(char * name)72dbed73cbSSangeeta Misra i_ilbd_alloc_sg(char *name)
73dbed73cbSSangeeta Misra {
74dbed73cbSSangeeta Misra 	ilbd_sg_t	*d_sg;
75dbed73cbSSangeeta Misra 
76dbed73cbSSangeeta Misra 	d_sg = calloc(sizeof (*d_sg), 1);
77dbed73cbSSangeeta Misra 	if (d_sg == NULL)
78dbed73cbSSangeeta Misra 		goto out;
79dbed73cbSSangeeta Misra 
80dbed73cbSSangeeta Misra 	(void) strlcpy(d_sg->isg_name, name, sizeof (d_sg->isg_name));
81dbed73cbSSangeeta Misra 
82dbed73cbSSangeeta Misra 	list_create(&d_sg->isg_srvlist, sizeof (ilbd_srv_t),
83dbed73cbSSangeeta Misra 	    offsetof(ilbd_srv_t, isv_srv_link));
84dbed73cbSSangeeta Misra 	list_create(&d_sg->isg_rulelist, sizeof (ilbd_rule_t),
85dbed73cbSSangeeta Misra 	    offsetof(ilbd_rule_t, irl_sglink));
86dbed73cbSSangeeta Misra 
87dbed73cbSSangeeta Misra 	list_insert_tail(&ilbd_sg_hlist, d_sg);
88dbed73cbSSangeeta Misra out:
89dbed73cbSSangeeta Misra 	return (d_sg);
90dbed73cbSSangeeta Misra }
91dbed73cbSSangeeta Misra 
92dbed73cbSSangeeta Misra static ilb_status_t
i_ilbd_save_sg(ilbd_sg_t * d_sg,ilbd_scf_cmd_t scf_cmd,const char * prop_name,char * valstr)93dbed73cbSSangeeta Misra i_ilbd_save_sg(ilbd_sg_t *d_sg, ilbd_scf_cmd_t scf_cmd, const char *prop_name,
94dbed73cbSSangeeta Misra     char *valstr)
95dbed73cbSSangeeta Misra {
96dbed73cbSSangeeta Misra 	switch (scf_cmd) {
97dbed73cbSSangeeta Misra 	case ILBD_SCF_CREATE:
98dbed73cbSSangeeta Misra 		return (ilbd_create_pg(ILBD_SCF_SG, (void *)d_sg));
99dbed73cbSSangeeta Misra 	case ILBD_SCF_DESTROY:
100dbed73cbSSangeeta Misra 		return (ilbd_destroy_pg(ILBD_SCF_SG, d_sg->isg_name));
101dbed73cbSSangeeta Misra 	case ILBD_SCF_ENABLE_DISABLE:
102dbed73cbSSangeeta Misra 		if (prop_name == NULL)
103dbed73cbSSangeeta Misra 			return (ILB_STATUS_EINVAL);
104dbed73cbSSangeeta Misra 		return (ilbd_change_prop(ILBD_SCF_SG, d_sg->isg_name,
105dbed73cbSSangeeta Misra 		    prop_name, valstr));
106dbed73cbSSangeeta Misra 	default:
107dbed73cbSSangeeta Misra 		logdebug("i_ilbd_save_sg: invalid scf cmd %d", scf_cmd);
108dbed73cbSSangeeta Misra 		return (ILB_STATUS_EINVAL);
109dbed73cbSSangeeta Misra 	}
110dbed73cbSSangeeta Misra }
111dbed73cbSSangeeta Misra 
112dbed73cbSSangeeta Misra ilb_status_t
i_attach_rule2sg(ilbd_sg_t * sg,ilbd_rule_t * irl)113dbed73cbSSangeeta Misra i_attach_rule2sg(ilbd_sg_t *sg, ilbd_rule_t *irl)
114dbed73cbSSangeeta Misra {
115dbed73cbSSangeeta Misra 	/* assert: the same rule is attached to any sg only once */
116dbed73cbSSangeeta Misra 	list_insert_tail(&sg->isg_rulelist, irl);
117dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
118dbed73cbSSangeeta Misra }
119dbed73cbSSangeeta Misra 
120dbed73cbSSangeeta Misra static void
i_ilbd_free_sg(ilbd_sg_t * sg)121dbed73cbSSangeeta Misra i_ilbd_free_sg(ilbd_sg_t *sg)
122dbed73cbSSangeeta Misra {
123dbed73cbSSangeeta Misra 	ilbd_srv_t *tmp_srv;
124dbed73cbSSangeeta Misra 
125dbed73cbSSangeeta Misra 	if (sg == NULL)
126dbed73cbSSangeeta Misra 		return;
127dbed73cbSSangeeta Misra 	list_remove(&ilbd_sg_hlist, sg);
128dbed73cbSSangeeta Misra 	while ((tmp_srv = list_remove_tail(&sg->isg_srvlist)) != NULL) {
129dbed73cbSSangeeta Misra 		i_ilbd_free_srvID(sg, tmp_srv->isv_id);
130dbed73cbSSangeeta Misra 		free(tmp_srv);
131dbed73cbSSangeeta Misra 		sg->isg_srvcount--;
132dbed73cbSSangeeta Misra 	}
133dbed73cbSSangeeta Misra 	free(sg);
134dbed73cbSSangeeta Misra }
135dbed73cbSSangeeta Misra 
136dbed73cbSSangeeta Misra ilbd_sg_t *
i_find_sg_byname(const char * name)137dbed73cbSSangeeta Misra i_find_sg_byname(const char *name)
138dbed73cbSSangeeta Misra {
139dbed73cbSSangeeta Misra 	ilbd_sg_t *sg;
140dbed73cbSSangeeta Misra 
141dbed73cbSSangeeta Misra 	/* find position of sg in list */
142dbed73cbSSangeeta Misra 	for (sg = list_head(&ilbd_sg_hlist); sg != NULL;
143dbed73cbSSangeeta Misra 	    sg = list_next(&ilbd_sg_hlist, sg)) {
144dbed73cbSSangeeta Misra 		if (strncmp(sg->isg_name, name, sizeof (sg->isg_name)) == 0)
145dbed73cbSSangeeta Misra 			return (sg);
146dbed73cbSSangeeta Misra 	}
147dbed73cbSSangeeta Misra 	return (sg);
148dbed73cbSSangeeta Misra }
149dbed73cbSSangeeta Misra 
150dbed73cbSSangeeta Misra /*
151dbed73cbSSangeeta Misra  * Generates an audit record for enable-server, disable-server, remove-server
152dbed73cbSSangeeta Misra  * delete-servergroup, create-servergroup and add-server subcommands.
153dbed73cbSSangeeta Misra  */
154dbed73cbSSangeeta Misra static void
ilbd_audit_server_event(audit_sg_event_data_t * data,ilbd_cmd_t cmd,ilb_status_t rc,ucred_t * ucredp)155dbed73cbSSangeeta Misra ilbd_audit_server_event(audit_sg_event_data_t *data,
156dbed73cbSSangeeta Misra     ilbd_cmd_t cmd, ilb_status_t rc, ucred_t *ucredp)
157dbed73cbSSangeeta Misra {
158dbed73cbSSangeeta Misra 	adt_session_data_t	*ah;
159dbed73cbSSangeeta Misra 	adt_event_data_t	*event;
160dbed73cbSSangeeta Misra 	au_event_t	flag;
161dbed73cbSSangeeta Misra 	int	audit_error;
162dbed73cbSSangeeta Misra 
163dbed73cbSSangeeta Misra 	if ((ucredp == NULL) && ((cmd == ILBD_ADD_SERVER_TO_GROUP) ||
164dbed73cbSSangeeta Misra 	    (cmd == ILBD_CREATE_SERVERGROUP)))  {
165dbed73cbSSangeeta Misra 		/*
166dbed73cbSSangeeta Misra 		 * We came here from the path where ilbd is
167dbed73cbSSangeeta Misra 		 * incorporating the ILB configuration from
168dbed73cbSSangeeta Misra 		 * SCF. In that case, we skip auditing
169dbed73cbSSangeeta Misra 		 */
170dbed73cbSSangeeta Misra 		return;
171dbed73cbSSangeeta Misra 	}
172dbed73cbSSangeeta Misra 
173dbed73cbSSangeeta Misra 	if (adt_start_session(&ah, NULL, 0) != 0) {
174dbed73cbSSangeeta Misra 		logerr("ilbd_audit_server_event: adt_start_session failed");
175dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
176dbed73cbSSangeeta Misra 	}
177dbed73cbSSangeeta Misra 
178dbed73cbSSangeeta Misra 	if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) {
179dbed73cbSSangeeta Misra 		(void) adt_end_session(ah);
180dbed73cbSSangeeta Misra 		logerr("ilbd_audit_server_event: adt_set_from_ucred failed");
181dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
182dbed73cbSSangeeta Misra 	}
183dbed73cbSSangeeta Misra 
184dbed73cbSSangeeta Misra 	if (cmd == ILBD_ENABLE_SERVER)
185dbed73cbSSangeeta Misra 		flag = ADT_ilb_enable_server;
186dbed73cbSSangeeta Misra 	else if (cmd == ILBD_DISABLE_SERVER)
187dbed73cbSSangeeta Misra 		flag = ADT_ilb_disable_server;
188dbed73cbSSangeeta Misra 	else if (cmd == ILBD_REM_SERVER_FROM_GROUP)
189dbed73cbSSangeeta Misra 		flag = ADT_ilb_remove_server;
190dbed73cbSSangeeta Misra 	else if (cmd == ILBD_ADD_SERVER_TO_GROUP)
191dbed73cbSSangeeta Misra 		flag = ADT_ilb_add_server;
192dbed73cbSSangeeta Misra 	else if (cmd == ILBD_CREATE_SERVERGROUP)
193dbed73cbSSangeeta Misra 		flag = ADT_ilb_create_servergroup;
194dbed73cbSSangeeta Misra 	else if (cmd == ILBD_DESTROY_SERVERGROUP)
195dbed73cbSSangeeta Misra 		flag = ADT_ilb_delete_servergroup;
196dbed73cbSSangeeta Misra 
197dbed73cbSSangeeta Misra 	if ((event = adt_alloc_event(ah, flag)) == NULL) {
198dbed73cbSSangeeta Misra 		logerr("ilbd_audit_server_event: adt_alloc_event failed");
199dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
200dbed73cbSSangeeta Misra 	}
201dbed73cbSSangeeta Misra 	(void) memset((char *)event, 0, sizeof (adt_event_data_t));
202dbed73cbSSangeeta Misra 
203dbed73cbSSangeeta Misra 	switch (cmd) {
204dbed73cbSSangeeta Misra 	case ILBD_ENABLE_SERVER:
205dbed73cbSSangeeta Misra 		event->adt_ilb_enable_server.auth_used =
206dbed73cbSSangeeta Misra 		    NET_ILB_ENABLE_AUTH;
207dbed73cbSSangeeta Misra 		event->adt_ilb_enable_server.server_id =
208dbed73cbSSangeeta Misra 		    data->ed_serverid;
2095df82708SSangeeta Misra 		event->adt_ilb_enable_server.server_ipaddress_type =
2105df82708SSangeeta Misra 		    data->ed_ipaddr_type;
2115df82708SSangeeta Misra 		(void) memcpy(event->adt_ilb_enable_server.server_ipaddress,
2125df82708SSangeeta Misra 		    data->ed_server_address,
2135df82708SSangeeta Misra 		    (sizeof (data->ed_server_address)));
214dbed73cbSSangeeta Misra 		break;
215dbed73cbSSangeeta Misra 	case ILBD_DISABLE_SERVER:
216dbed73cbSSangeeta Misra 		event->adt_ilb_disable_server.auth_used =
217dbed73cbSSangeeta Misra 		    NET_ILB_ENABLE_AUTH;
218dbed73cbSSangeeta Misra 		event->adt_ilb_disable_server.server_id =
219dbed73cbSSangeeta Misra 		    data->ed_serverid;
2205df82708SSangeeta Misra 		event->adt_ilb_disable_server.server_ipaddress_type =
2215df82708SSangeeta Misra 		    data->ed_ipaddr_type;
2225df82708SSangeeta Misra 		(void) memcpy(event->adt_ilb_disable_server.server_ipaddress,
2235df82708SSangeeta Misra 		    data->ed_server_address,
2245df82708SSangeeta Misra 		    (sizeof (data->ed_server_address)));
225dbed73cbSSangeeta Misra 		break;
226dbed73cbSSangeeta Misra 	case ILBD_REM_SERVER_FROM_GROUP:
227dbed73cbSSangeeta Misra 		event->adt_ilb_remove_server.auth_used =
228dbed73cbSSangeeta Misra 		    NET_ILB_CONFIG_AUTH;
229dbed73cbSSangeeta Misra 		event->adt_ilb_remove_server.server_id =
230dbed73cbSSangeeta Misra 		    data->ed_serverid;
231dbed73cbSSangeeta Misra 		event->adt_ilb_remove_server.server_group = data->ed_sgroup;
2325df82708SSangeeta Misra 		event->adt_ilb_remove_server.server_ipaddress_type =
2335df82708SSangeeta Misra 		    data->ed_ipaddr_type;
2345df82708SSangeeta Misra 		(void) memcpy(event->adt_ilb_remove_server.server_ipaddress,
2355df82708SSangeeta Misra 		    data->ed_server_address,
2365df82708SSangeeta Misra 		    (sizeof (data->ed_server_address)));
237dbed73cbSSangeeta Misra 		break;
238dbed73cbSSangeeta Misra 	case ILBD_CREATE_SERVERGROUP:
239dbed73cbSSangeeta Misra 		event->adt_ilb_create_servergroup.auth_used =
240dbed73cbSSangeeta Misra 		    NET_ILB_CONFIG_AUTH;
241dbed73cbSSangeeta Misra 		event->adt_ilb_create_servergroup.server_group =
242dbed73cbSSangeeta Misra 		    data->ed_sgroup;
243dbed73cbSSangeeta Misra 		break;
244dbed73cbSSangeeta Misra 	case ILBD_ADD_SERVER_TO_GROUP:
245dbed73cbSSangeeta Misra 		event->adt_ilb_add_server.auth_used =
246dbed73cbSSangeeta Misra 		    NET_ILB_CONFIG_AUTH;
2475df82708SSangeeta Misra 		event->adt_ilb_add_server.server_ipaddress_type =
2485df82708SSangeeta Misra 		    data->ed_ipaddr_type;
2495df82708SSangeeta Misra 		(void) memcpy(event->adt_ilb_add_server.server_ipaddress,
2505df82708SSangeeta Misra 		    data->ed_server_address,
2515df82708SSangeeta Misra 		    (sizeof (data->ed_server_address)));
252dbed73cbSSangeeta Misra 		event->adt_ilb_add_server.server_id =
253dbed73cbSSangeeta Misra 		    data->ed_serverid;
254dbed73cbSSangeeta Misra 		event->adt_ilb_add_server.server_group =
255dbed73cbSSangeeta Misra 		    data->ed_sgroup;
256dbed73cbSSangeeta Misra 		event->adt_ilb_add_server.server_minport =
257dbed73cbSSangeeta Misra 		    ntohs(data->ed_minport);
258dbed73cbSSangeeta Misra 		event->adt_ilb_add_server.server_maxport =
259dbed73cbSSangeeta Misra 		    ntohs(data->ed_maxport);
260dbed73cbSSangeeta Misra 		break;
261dbed73cbSSangeeta Misra 	case ILBD_DESTROY_SERVERGROUP:
262dbed73cbSSangeeta Misra 		event->adt_ilb_delete_servergroup.auth_used =
263dbed73cbSSangeeta Misra 		    NET_ILB_CONFIG_AUTH;
264dbed73cbSSangeeta Misra 		event->adt_ilb_delete_servergroup.server_group =
265dbed73cbSSangeeta Misra 		    data->ed_sgroup;
266dbed73cbSSangeeta Misra 		break;
267dbed73cbSSangeeta Misra 	}
268dbed73cbSSangeeta Misra 
269dbed73cbSSangeeta Misra 	/* Fill in success/failure */
270dbed73cbSSangeeta Misra 	if (rc == ILB_STATUS_OK) {
271dbed73cbSSangeeta Misra 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
272dbed73cbSSangeeta Misra 			logerr("ilbd_audit_server_event:"
273dbed73cbSSangeeta Misra 			    " adt_put_event failed");
274dbed73cbSSangeeta Misra 			exit(EXIT_FAILURE);
275dbed73cbSSangeeta Misra 		}
276dbed73cbSSangeeta Misra 	} else {
277dbed73cbSSangeeta Misra 		audit_error = ilberror2auditerror(rc);
278dbed73cbSSangeeta Misra 		if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) {
279dbed73cbSSangeeta Misra 			logerr("ilbd_audit_server_event:"
280dbed73cbSSangeeta Misra 			    " adt_put_event failed");
281dbed73cbSSangeeta Misra 			exit(EXIT_FAILURE);
282dbed73cbSSangeeta Misra 		}
283dbed73cbSSangeeta Misra 	}
284dbed73cbSSangeeta Misra 	adt_free_event(event);
285dbed73cbSSangeeta Misra 	(void) adt_end_session(ah);
286dbed73cbSSangeeta Misra }
287dbed73cbSSangeeta Misra 
288dbed73cbSSangeeta Misra ilb_status_t
ilbd_destroy_sg(const char * sg_name,const struct passwd * ps,ucred_t * ucredp)289dbed73cbSSangeeta Misra ilbd_destroy_sg(const char *sg_name, const struct passwd *ps,
290dbed73cbSSangeeta Misra     ucred_t *ucredp)
291dbed73cbSSangeeta Misra {
292dbed73cbSSangeeta Misra 	ilb_status_t	rc;
293dbed73cbSSangeeta Misra 	ilbd_sg_t	*tmp_sg;
294dbed73cbSSangeeta Misra 	audit_sg_event_data_t   audit_sg_data;
295dbed73cbSSangeeta Misra 
296dbed73cbSSangeeta Misra 	(void) memset(&audit_sg_data, 0, sizeof (audit_sg_event_data_t));
297dbed73cbSSangeeta Misra 	audit_sg_data.ed_sgroup = (char *)sg_name;
298dbed73cbSSangeeta Misra 
299dbed73cbSSangeeta Misra 	rc = ilbd_check_client_config_auth(ps);
300dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK) {
301dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
302dbed73cbSSangeeta Misra 		    ILBD_DESTROY_SERVERGROUP, rc, ucredp);
303dbed73cbSSangeeta Misra 		return (rc);
304dbed73cbSSangeeta Misra 	}
305dbed73cbSSangeeta Misra 
306dbed73cbSSangeeta Misra 	tmp_sg = i_find_sg_byname(sg_name);
307dbed73cbSSangeeta Misra 	if (tmp_sg == NULL) {
308dbed73cbSSangeeta Misra 		logdebug("ilbd_destroy_sg: cannot find specified server"
309dbed73cbSSangeeta Misra 		    " group %s", sg_name);
310dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
311dbed73cbSSangeeta Misra 		    ILBD_DESTROY_SERVERGROUP, ILB_STATUS_SGUNAVAIL, ucredp);
312dbed73cbSSangeeta Misra 		return (ILB_STATUS_SGUNAVAIL);
313dbed73cbSSangeeta Misra 	}
314dbed73cbSSangeeta Misra 
315dbed73cbSSangeeta Misra 	/*
316dbed73cbSSangeeta Misra 	 * we only destroy SGs that don't have any rules associated with
317dbed73cbSSangeeta Misra 	 * them anymore.
318dbed73cbSSangeeta Misra 	 */
319dbed73cbSSangeeta Misra 	if (list_head(&tmp_sg->isg_rulelist) != NULL) {
320dbed73cbSSangeeta Misra 		logdebug("ilbd_destroy_sg: server group %s has rules"
321dbed73cbSSangeeta Misra 		" associated with it and thus cannot be"
322dbed73cbSSangeeta Misra 		    " removed", tmp_sg->isg_name);
323dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
324dbed73cbSSangeeta Misra 		    ILBD_DESTROY_SERVERGROUP, ILB_STATUS_SGINUSE, ucredp);
325dbed73cbSSangeeta Misra 		return (ILB_STATUS_SGINUSE);
326dbed73cbSSangeeta Misra 	}
327dbed73cbSSangeeta Misra 
328dbed73cbSSangeeta Misra 	if (ps != NULL) {
329dbed73cbSSangeeta Misra 		rc = i_ilbd_save_sg(tmp_sg, ILBD_SCF_DESTROY, NULL, NULL);
330dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
331dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
332dbed73cbSSangeeta Misra 		    ILBD_DESTROY_SERVERGROUP, rc, ucredp);
333dbed73cbSSangeeta Misra 			return (rc);
334dbed73cbSSangeeta Misra 		}
335dbed73cbSSangeeta Misra 	}
336dbed73cbSSangeeta Misra 	i_ilbd_free_sg(tmp_sg);
337dbed73cbSSangeeta Misra 	ilbd_audit_server_event(&audit_sg_data, ILBD_DESTROY_SERVERGROUP,
338dbed73cbSSangeeta Misra 	    rc, ucredp);
339dbed73cbSSangeeta Misra 	return (rc);
340dbed73cbSSangeeta Misra }
341dbed73cbSSangeeta Misra 
342dbed73cbSSangeeta Misra /* ARGSUSED */
343dbed73cbSSangeeta Misra /*
344dbed73cbSSangeeta Misra  * Parameter ev_port is not used but has to have for read persistent configure
345dbed73cbSSangeeta Misra  * ilbd_create_sg(), ilbd_create_hc() and ilbd_create_rule() are callbacks
346dbed73cbSSangeeta Misra  * for ilbd_scf_instance_walk_pg() which requires the same signature.
347dbed73cbSSangeeta Misra  */
348dbed73cbSSangeeta Misra ilb_status_t
ilbd_create_sg(ilb_sg_info_t * sg,int ev_port,const struct passwd * ps,ucred_t * ucredp)349dbed73cbSSangeeta Misra ilbd_create_sg(ilb_sg_info_t *sg, int ev_port, const struct passwd *ps,
350dbed73cbSSangeeta Misra     ucred_t *ucredp)
351dbed73cbSSangeeta Misra {
352dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
353dbed73cbSSangeeta Misra 	ilbd_sg_t	*d_sg;
354dbed73cbSSangeeta Misra 	audit_sg_event_data_t   audit_sg_data;
355dbed73cbSSangeeta Misra 
356dbed73cbSSangeeta Misra 	(void) memset(&audit_sg_data, 0, sizeof (audit_sg_event_data_t));
357dbed73cbSSangeeta Misra 	audit_sg_data.ed_sgroup = sg->sg_name;
358dbed73cbSSangeeta Misra 
359dbed73cbSSangeeta Misra 	if (ps != NULL) {
360dbed73cbSSangeeta Misra 		rc = ilbd_check_client_config_auth(ps);
361dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
362dbed73cbSSangeeta Misra 			ilbd_audit_server_event(&audit_sg_data,
363dbed73cbSSangeeta Misra 			    ILBD_CREATE_SERVERGROUP, rc, ucredp);
364dbed73cbSSangeeta Misra 			return (rc);
365dbed73cbSSangeeta Misra 		}
366dbed73cbSSangeeta Misra 	}
367dbed73cbSSangeeta Misra 
368dbed73cbSSangeeta Misra 	if (i_find_sg_byname(sg->sg_name) != NULL) {
369dbed73cbSSangeeta Misra 		logdebug("ilbd_create_sg: server group %s already exists",
370dbed73cbSSangeeta Misra 		    sg->sg_name);
371dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
372dbed73cbSSangeeta Misra 		    ILBD_CREATE_SERVERGROUP, ILB_STATUS_SGEXISTS, ucredp);
373dbed73cbSSangeeta Misra 		return (ILB_STATUS_SGEXISTS);
374dbed73cbSSangeeta Misra 	}
375dbed73cbSSangeeta Misra 
376dbed73cbSSangeeta Misra 	d_sg = i_ilbd_alloc_sg(sg->sg_name);
377dbed73cbSSangeeta Misra 	if (d_sg == NULL) {
378dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
379dbed73cbSSangeeta Misra 		    ILBD_CREATE_SERVERGROUP, ILB_STATUS_ENOMEM, ucredp);
380dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
381dbed73cbSSangeeta Misra 	}
382dbed73cbSSangeeta Misra 
383dbed73cbSSangeeta Misra 	/*
384dbed73cbSSangeeta Misra 	 * we've successfully created the sg in memory. Before we can
385dbed73cbSSangeeta Misra 	 * return "success", we need to reflect this in persistent
386dbed73cbSSangeeta Misra 	 * storage
387dbed73cbSSangeeta Misra 	 */
388dbed73cbSSangeeta Misra 	if (ps != NULL) {
389dbed73cbSSangeeta Misra 		rc = i_ilbd_save_sg(d_sg, ILBD_SCF_CREATE, NULL, NULL);
390dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
391dbed73cbSSangeeta Misra 			i_ilbd_free_sg(d_sg);
392dbed73cbSSangeeta Misra 			ilbd_audit_server_event(&audit_sg_data,
393dbed73cbSSangeeta Misra 			    ILBD_CREATE_SERVERGROUP, rc, ucredp);
394dbed73cbSSangeeta Misra 			return (rc);
395dbed73cbSSangeeta Misra 		}
396dbed73cbSSangeeta Misra 	}
397dbed73cbSSangeeta Misra 	ilbd_audit_server_event(&audit_sg_data,
398dbed73cbSSangeeta Misra 	    ILBD_CREATE_SERVERGROUP, rc, ucredp);
399dbed73cbSSangeeta Misra 	return (rc);
400dbed73cbSSangeeta Misra }
401dbed73cbSSangeeta Misra 
402dbed73cbSSangeeta Misra /*
403dbed73cbSSangeeta Misra  * This function checks whether tsrv should/can be inserted before lsrv
404dbed73cbSSangeeta Misra  * and does so if possible.
405dbed73cbSSangeeta Misra  * We keep the list in sorted order so we don't have to search it
406dbed73cbSSangeeta Misra  * in its entirety for overlap every time we insert a new server.
407dbed73cbSSangeeta Misra  * Return code:
408dbed73cbSSangeeta Misra  *	stop_found: don't continue searching because we found a place
409dbed73cbSSangeeta Misra  *	cont_search: continue with next element in the list
410dbed73cbSSangeeta Misra  *	fail_search: search failed (caller translates to ILB_STATUS_EEXIST)
411dbed73cbSSangeeta Misra  */
412dbed73cbSSangeeta Misra static srch_ind_t
i_test_and_insert(ilbd_srv_t * tsrv,ilbd_srv_t * lsrv,list_t * srvlist)413dbed73cbSSangeeta Misra i_test_and_insert(ilbd_srv_t *tsrv, ilbd_srv_t *lsrv, list_t *srvlist)
414dbed73cbSSangeeta Misra {
415dbed73cbSSangeeta Misra 	struct in6_addr	*t1, *l1;
416dbed73cbSSangeeta Misra 	int		fnd;
417dbed73cbSSangeeta Misra 
418dbed73cbSSangeeta Misra 	t1 = &tsrv->isv_addr;
419dbed73cbSSangeeta Misra 	l1 = &lsrv->isv_addr;
420dbed73cbSSangeeta Misra 
421dbed73cbSSangeeta Misra 	if ((fnd = ilb_cmp_in6_addr(t1, l1, NULL)) == 1)
422dbed73cbSSangeeta Misra 		return (cont_search);	/* search can continue */
423dbed73cbSSangeeta Misra 
424dbed73cbSSangeeta Misra 	if (fnd == 0) {
425dbed73cbSSangeeta Misra 		logdebug("i_test_and_insert: specified server already exists");
426dbed73cbSSangeeta Misra 		return (fail_search);
427dbed73cbSSangeeta Misra 	}
428dbed73cbSSangeeta Misra 	/* the list is kept in ascending order */
429dbed73cbSSangeeta Misra 	list_insert_before(srvlist, lsrv, tsrv);
430dbed73cbSSangeeta Misra 	return (stop_found);
431dbed73cbSSangeeta Misra }
432dbed73cbSSangeeta Misra 
433dbed73cbSSangeeta Misra 
434dbed73cbSSangeeta Misra /*
435dbed73cbSSangeeta Misra  * copy a server description [ip1,ip2,port1,port2,srvID,flags]
436dbed73cbSSangeeta Misra  */
437dbed73cbSSangeeta Misra #define	COPY_SERVER(src, dest)					\
438dbed73cbSSangeeta Misra 	(dest)->sgs_addr = (src)->sgs_addr;			\
439dbed73cbSSangeeta Misra 	(dest)->sgs_minport = (src)->sgs_minport;		\
440dbed73cbSSangeeta Misra 	(dest)->sgs_maxport = (src)->sgs_maxport;		\
441dbed73cbSSangeeta Misra 	(dest)->sgs_id = (src)->sgs_id;				\
442dbed73cbSSangeeta Misra 	(void) strlcpy((dest)->sgs_srvID, (src)->sgs_srvID,	\
443dbed73cbSSangeeta Misra 	    sizeof ((dest)->sgs_srvID));			\
444dbed73cbSSangeeta Misra 	(dest)->sgs_flags = (src)->sgs_flags
445dbed73cbSSangeeta Misra 
446dbed73cbSSangeeta Misra static ilb_status_t
i_add_srv2sg(ilbd_sg_t * dsg,ilb_sg_srv_t * srv,ilbd_srv_t ** ret_srv)447dbed73cbSSangeeta Misra i_add_srv2sg(ilbd_sg_t *dsg, ilb_sg_srv_t *srv, ilbd_srv_t **ret_srv)
448dbed73cbSSangeeta Misra {
449dbed73cbSSangeeta Misra 	ilb_sg_srv_t	*n_sg_srv;
450dbed73cbSSangeeta Misra 	list_t		*srvlist;
451dbed73cbSSangeeta Misra 	srch_ind_t	search = not_searched;
452dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
453dbed73cbSSangeeta Misra 	ilbd_srv_t	*nsrv, *lsrv;
454dbed73cbSSangeeta Misra 	in_port_t	h_minport, h_maxport;
455dbed73cbSSangeeta Misra 
456dbed73cbSSangeeta Misra 	nsrv = calloc(sizeof (*nsrv), 1);
457dbed73cbSSangeeta Misra 	if (nsrv == NULL)
458dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
459dbed73cbSSangeeta Misra 	n_sg_srv = &nsrv->isv_srv;
460dbed73cbSSangeeta Misra 	COPY_SERVER(srv, n_sg_srv);
461dbed73cbSSangeeta Misra 
462dbed73cbSSangeeta Misra 	/*
463dbed73cbSSangeeta Misra 	 * port info is in network byte order - we need host byte order
464dbed73cbSSangeeta Misra 	 * for comparisons purposes
465dbed73cbSSangeeta Misra 	 */
466dbed73cbSSangeeta Misra 	h_minport = ntohs(n_sg_srv->sgs_minport);
467dbed73cbSSangeeta Misra 	h_maxport = ntohs(n_sg_srv->sgs_maxport);
468dbed73cbSSangeeta Misra 	if (h_minport != 0 && h_minport > h_maxport)
469dbed73cbSSangeeta Misra 		n_sg_srv->sgs_maxport = n_sg_srv->sgs_minport;
470dbed73cbSSangeeta Misra 
471dbed73cbSSangeeta Misra 	srvlist = &dsg->isg_srvlist;
472dbed73cbSSangeeta Misra 
473dbed73cbSSangeeta Misra 	lsrv = list_head(srvlist);
474dbed73cbSSangeeta Misra 	if (lsrv == NULL) {
475dbed73cbSSangeeta Misra 		list_insert_head(srvlist, nsrv);
476dbed73cbSSangeeta Misra 	} else {
477dbed73cbSSangeeta Misra 		while (lsrv != NULL) {
478dbed73cbSSangeeta Misra 			search = i_test_and_insert(nsrv, lsrv,
479dbed73cbSSangeeta Misra 			    srvlist);
480dbed73cbSSangeeta Misra 
481dbed73cbSSangeeta Misra 			if (search != cont_search)
482dbed73cbSSangeeta Misra 				break;
483dbed73cbSSangeeta Misra 			lsrv = list_next(srvlist, lsrv);
484dbed73cbSSangeeta Misra 
485dbed73cbSSangeeta Misra 			/* if reaches the end of list, insert to the tail */
486dbed73cbSSangeeta Misra 			if (search == cont_search && lsrv == NULL)
487dbed73cbSSangeeta Misra 				list_insert_tail(srvlist, nsrv);
488dbed73cbSSangeeta Misra 		}
489dbed73cbSSangeeta Misra 		if (search == fail_search)
490dbed73cbSSangeeta Misra 			rc = ILB_STATUS_EEXIST;
491dbed73cbSSangeeta Misra 	}
492dbed73cbSSangeeta Misra 
493dbed73cbSSangeeta Misra 	if (rc == ILB_STATUS_OK) {
494dbed73cbSSangeeta Misra 		dsg->isg_srvcount++;
495dbed73cbSSangeeta Misra 		*ret_srv = nsrv;
496dbed73cbSSangeeta Misra 	} else {
497dbed73cbSSangeeta Misra 		free(nsrv);
498dbed73cbSSangeeta Misra 	}
499dbed73cbSSangeeta Misra 
500dbed73cbSSangeeta Misra 	return (rc);
501dbed73cbSSangeeta Misra }
502dbed73cbSSangeeta Misra 
503dbed73cbSSangeeta Misra /*
504dbed73cbSSangeeta Misra  * Allocate a server ID.  The algorithm is simple.  Just check the ID array
505dbed73cbSSangeeta Misra  * of the server group and find an unused ID.  If *set_id is given, it
506dbed73cbSSangeeta Misra  * means that the ID is already allocated and the ID array needs to be
507dbed73cbSSangeeta Misra  * updated.  This is the case when ilbd reads from the persistent
508dbed73cbSSangeeta Misra  * configuration.
509dbed73cbSSangeeta Misra  */
510dbed73cbSSangeeta Misra static int32_t
i_ilbd_alloc_srvID(ilbd_sg_t * sg,int32_t * set_id)511dbed73cbSSangeeta Misra i_ilbd_alloc_srvID(ilbd_sg_t *sg, int32_t *set_id)
512dbed73cbSSangeeta Misra {
513dbed73cbSSangeeta Misra 	int32_t		id;
514dbed73cbSSangeeta Misra 	int32_t		i;
515dbed73cbSSangeeta Misra 
516dbed73cbSSangeeta Misra 	/* The server ID is already allocated, just update the ID array. */
517dbed73cbSSangeeta Misra 	if (set_id != NULL) {
518dbed73cbSSangeeta Misra 		assert(sg->isg_id_arr[*set_id] == 0);
519dbed73cbSSangeeta Misra 		sg->isg_id_arr[*set_id] = 1;
520dbed73cbSSangeeta Misra 		return (*set_id);
521dbed73cbSSangeeta Misra 	}
522dbed73cbSSangeeta Misra 
523dbed73cbSSangeeta Misra 	/* if we're "full up", give back something invalid */
524dbed73cbSSangeeta Misra 	if (sg->isg_srvcount == MAX_SRVCOUNT)
525dbed73cbSSangeeta Misra 		return (BAD_SRVID);
526dbed73cbSSangeeta Misra 
527dbed73cbSSangeeta Misra 	i = sg->isg_max_id;
528dbed73cbSSangeeta Misra 	for (id = 0; id < MAX_SRVCOUNT; id++) {
529dbed73cbSSangeeta Misra 		if (sg->isg_id_arr[(id + i) % MAX_SRVCOUNT] == 0)
530dbed73cbSSangeeta Misra 			break;
531dbed73cbSSangeeta Misra 	}
532dbed73cbSSangeeta Misra 
533dbed73cbSSangeeta Misra 	sg->isg_max_id = (id + i) % MAX_SRVCOUNT;
534dbed73cbSSangeeta Misra 	sg->isg_id_arr[sg->isg_max_id] = 1;
535dbed73cbSSangeeta Misra 	return (sg->isg_max_id);
536dbed73cbSSangeeta Misra }
537dbed73cbSSangeeta Misra 
538dbed73cbSSangeeta Misra /*
539dbed73cbSSangeeta Misra  * Free a server ID by updating the server group's ID array.
540dbed73cbSSangeeta Misra  */
541dbed73cbSSangeeta Misra static void
i_ilbd_free_srvID(ilbd_sg_t * sg,int32_t id)542dbed73cbSSangeeta Misra i_ilbd_free_srvID(ilbd_sg_t *sg, int32_t id)
543dbed73cbSSangeeta Misra {
544dbed73cbSSangeeta Misra 	assert(sg->isg_id_arr[id] == 1);
545dbed73cbSSangeeta Misra 	sg->isg_id_arr[id] = 0;
546dbed73cbSSangeeta Misra }
547dbed73cbSSangeeta Misra 
548dbed73cbSSangeeta Misra /*
549dbed73cbSSangeeta Misra  * This function is called by ilbd_add_server_to_group() and
550dbed73cbSSangeeta Misra  * ilb_remove_server_group() to create a audit record for a
551dbed73cbSSangeeta Misra  * failed servicing of add-server/remove-server command
552dbed73cbSSangeeta Misra  */
553dbed73cbSSangeeta Misra static void
fill_audit_record(ilb_sg_info_t * sg,audit_sg_event_data_t * audit_sg_data,ilbd_cmd_t cmd,ilb_status_t rc,ucred_t * ucredp)554dbed73cbSSangeeta Misra fill_audit_record(ilb_sg_info_t *sg, audit_sg_event_data_t *audit_sg_data,
555dbed73cbSSangeeta Misra     ilbd_cmd_t cmd, ilb_status_t rc, ucred_t *ucredp)
556dbed73cbSSangeeta Misra {
557dbed73cbSSangeeta Misra 	ilb_sg_srv_t	*tsrv;
558dbed73cbSSangeeta Misra 	int	i;
559dbed73cbSSangeeta Misra 
560dbed73cbSSangeeta Misra 	for (i = 0; i < sg->sg_srvcount; i++) {
561dbed73cbSSangeeta Misra 		tsrv = &sg->sg_servers[i];
562dbed73cbSSangeeta Misra 		if (cmd == ILBD_ADD_SERVER_TO_GROUP)  {
563dbed73cbSSangeeta Misra 
564dbed73cbSSangeeta Misra 			audit_sg_data->ed_serverid = NULL;
5655df82708SSangeeta Misra 			if (IN6_IS_ADDR_V4MAPPED(&tsrv->sgs_addr)) {
5665df82708SSangeeta Misra 				audit_sg_data->ed_ipaddr_type = ADT_IPv4;
5675df82708SSangeeta Misra 				cvt_addr(audit_sg_data->ed_server_address,
5685df82708SSangeeta Misra 				    ADT_IPv4, tsrv->sgs_addr);
5695df82708SSangeeta Misra 			} else {
5705df82708SSangeeta Misra 				audit_sg_data->ed_ipaddr_type = ADT_IPv6;
5715df82708SSangeeta Misra 				cvt_addr(audit_sg_data->ed_server_address,
5725df82708SSangeeta Misra 				    ADT_IPv6, tsrv->sgs_addr);
5735df82708SSangeeta Misra 			}
574dbed73cbSSangeeta Misra 			audit_sg_data->ed_minport = tsrv->sgs_minport;
575dbed73cbSSangeeta Misra 			audit_sg_data->ed_maxport = tsrv->sgs_maxport;
576dbed73cbSSangeeta Misra 			audit_sg_data->ed_sgroup = sg->sg_name;
577dbed73cbSSangeeta Misra 		} else if (cmd == ILBD_REM_SERVER_FROM_GROUP) {
578dbed73cbSSangeeta Misra 			audit_sg_data->ed_serverid = tsrv->sgs_srvID;
579dbed73cbSSangeeta Misra 			audit_sg_data->ed_sgroup = sg->sg_name;
5805df82708SSangeeta Misra 
581dbed73cbSSangeeta Misra 			audit_sg_data->ed_minport = 0;
582dbed73cbSSangeeta Misra 			audit_sg_data->ed_maxport = 0;
583dbed73cbSSangeeta Misra 		}
584dbed73cbSSangeeta Misra 		ilbd_audit_server_event(audit_sg_data, cmd, rc, ucredp);
585dbed73cbSSangeeta Misra 	}
586dbed73cbSSangeeta Misra }
587dbed73cbSSangeeta Misra 
588dbed73cbSSangeeta Misra /*
589dbed73cbSSangeeta Misra  * the name(s) of the server(s) are encoded in the sg.
590dbed73cbSSangeeta Misra  */
591dbed73cbSSangeeta Misra ilb_status_t
ilbd_add_server_to_group(ilb_sg_info_t * sg_info,int ev_port,const struct passwd * ps,ucred_t * ucredp)592dbed73cbSSangeeta Misra ilbd_add_server_to_group(ilb_sg_info_t *sg_info, int ev_port,
593dbed73cbSSangeeta Misra     const struct passwd *ps, ucred_t *ucredp)
594dbed73cbSSangeeta Misra {
595dbed73cbSSangeeta Misra 	ilb_status_t	rc = ILB_STATUS_OK;
596dbed73cbSSangeeta Misra 	ilbd_sg_t	*tmp_sg;
597dbed73cbSSangeeta Misra 	int		i, j;
598dbed73cbSSangeeta Misra 	int32_t		new_id = BAD_SRVID;
599dbed73cbSSangeeta Misra 	int32_t		af = AF_UNSPEC;
600dbed73cbSSangeeta Misra 	ilbd_srv_t	*nsrv;
601dbed73cbSSangeeta Misra 	ilb_sg_srv_t	*srv;
602dbed73cbSSangeeta Misra 	audit_sg_event_data_t   audit_sg_data;
603dbed73cbSSangeeta Misra 
604dbed73cbSSangeeta Misra 	if (ps != NULL) {
605dbed73cbSSangeeta Misra 		rc = ilbd_check_client_config_auth(ps);
606dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
607dbed73cbSSangeeta Misra 			fill_audit_record(sg_info, &audit_sg_data,
608dbed73cbSSangeeta Misra 			    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
609dbed73cbSSangeeta Misra 			return (rc);
610dbed73cbSSangeeta Misra 		}
611dbed73cbSSangeeta Misra 	}
612dbed73cbSSangeeta Misra 
613dbed73cbSSangeeta Misra 	tmp_sg = i_find_sg_byname(sg_info->sg_name);
614dbed73cbSSangeeta Misra 	if (tmp_sg == NULL) {
615dbed73cbSSangeeta Misra 		logdebug("ilbd_add_server_to_group: server"
616dbed73cbSSangeeta Misra 		    " group %s does not exist", sg_info->sg_name);
617dbed73cbSSangeeta Misra 		fill_audit_record(sg_info, &audit_sg_data,
618dbed73cbSSangeeta Misra 		    ILBD_ADD_SERVER_TO_GROUP, ILB_STATUS_ENOENT, ucredp);
619dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
620dbed73cbSSangeeta Misra 	}
621dbed73cbSSangeeta Misra 
622dbed73cbSSangeeta Misra 	/*
623dbed73cbSSangeeta Misra 	 * we do the dance with address family below to make sure only
624dbed73cbSSangeeta Misra 	 * IP addresses in the same AF get into an SG; the first one to get
625dbed73cbSSangeeta Misra 	 * in sets the "tone"
626dbed73cbSSangeeta Misra 	 * if this is the first server to join a group, check whether
627dbed73cbSSangeeta Misra 	 * there's no mismatch with any *rules* already attached
628dbed73cbSSangeeta Misra 	 */
629dbed73cbSSangeeta Misra 	if (tmp_sg->isg_srvcount > 0) {
630dbed73cbSSangeeta Misra 		ilbd_srv_t *tsrv = list_head(&tmp_sg->isg_srvlist);
631dbed73cbSSangeeta Misra 
632dbed73cbSSangeeta Misra 		af = GET_AF(&tsrv->isv_addr);
633dbed73cbSSangeeta Misra 	} else {
634dbed73cbSSangeeta Misra 		ilbd_rule_t	*irl = list_head(&tmp_sg->isg_rulelist);
635dbed73cbSSangeeta Misra 
636dbed73cbSSangeeta Misra 		if (irl != NULL)
637dbed73cbSSangeeta Misra 			af = GET_AF(&irl->irl_vip);
638dbed73cbSSangeeta Misra 	}
639dbed73cbSSangeeta Misra 
640dbed73cbSSangeeta Misra 	for (i = 0; i < sg_info->sg_srvcount; i++) {
641dbed73cbSSangeeta Misra 		srv = &sg_info->sg_servers[i];
642dbed73cbSSangeeta Misra 
643dbed73cbSSangeeta Misra 		(void) memset(&audit_sg_data, 0, sizeof (audit_sg_data));
6445df82708SSangeeta Misra 		if (IN6_IS_ADDR_V4MAPPED(&srv->sgs_addr)) {
6455df82708SSangeeta Misra 			audit_sg_data.ed_ipaddr_type = ADT_IPv4;
6465df82708SSangeeta Misra 			cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4,
6475df82708SSangeeta Misra 			    srv->sgs_addr);
6485df82708SSangeeta Misra 		} else {
6495df82708SSangeeta Misra 			audit_sg_data.ed_ipaddr_type = ADT_IPv6;
6505df82708SSangeeta Misra 			cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6,
6515df82708SSangeeta Misra 			    srv->sgs_addr);
6525df82708SSangeeta Misra 		}
653dbed73cbSSangeeta Misra 		audit_sg_data.ed_minport = srv->sgs_minport;
654dbed73cbSSangeeta Misra 		audit_sg_data.ed_maxport = srv->sgs_maxport;
655dbed73cbSSangeeta Misra 		audit_sg_data.ed_sgroup = sg_info->sg_name;
656dbed73cbSSangeeta Misra 
657dbed73cbSSangeeta Misra 		/* only test if we have sth to test against */
658dbed73cbSSangeeta Misra 		if (af != AF_UNSPEC) {
659dbed73cbSSangeeta Misra 			int32_t	sgs_af = GET_AF(&srv->sgs_addr);
660dbed73cbSSangeeta Misra 
661dbed73cbSSangeeta Misra 			if (af != sgs_af) {
662dbed73cbSSangeeta Misra 				logdebug("address family mismatch with previous"
663dbed73cbSSangeeta Misra 				    " hosts in servergroup or with rule");
664dbed73cbSSangeeta Misra 				rc = ILB_STATUS_MISMATCHH;
665dbed73cbSSangeeta Misra 				ilbd_audit_server_event(&audit_sg_data,
666dbed73cbSSangeeta Misra 				    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
667dbed73cbSSangeeta Misra 				goto rollback;
668dbed73cbSSangeeta Misra 			}
669dbed73cbSSangeeta Misra 		}
670dbed73cbSSangeeta Misra 
671dbed73cbSSangeeta Misra 		/*
672dbed73cbSSangeeta Misra 		 * PS: NULL means daemon is loading configure from scf.
673dbed73cbSSangeeta Misra 		 * ServerID is already assigned, just update the ID array.
674dbed73cbSSangeeta Misra 		 */
675dbed73cbSSangeeta Misra 		if (ps != NULL) {
676dbed73cbSSangeeta Misra 			new_id = i_ilbd_alloc_srvID(tmp_sg, NULL);
677dbed73cbSSangeeta Misra 			if (new_id == BAD_SRVID) {
678dbed73cbSSangeeta Misra 				logdebug("ilbd_add_server_to_group: server"
679dbed73cbSSangeeta Misra 				    "group %s is full, no more servers"
680dbed73cbSSangeeta Misra 				    " can be added", sg_info->sg_name);
681dbed73cbSSangeeta Misra 				rc = ILB_STATUS_SGFULL;
682dbed73cbSSangeeta Misra 				ilbd_audit_server_event(&audit_sg_data,
683dbed73cbSSangeeta Misra 				    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
684dbed73cbSSangeeta Misra 				goto rollback;
685dbed73cbSSangeeta Misra 			}
686dbed73cbSSangeeta Misra 			srv->sgs_id = new_id;
687dbed73cbSSangeeta Misra 		} else {
688dbed73cbSSangeeta Misra 			new_id = i_ilbd_alloc_srvID(tmp_sg, &srv->sgs_id);
689dbed73cbSSangeeta Misra 		}
690dbed73cbSSangeeta Misra 
691dbed73cbSSangeeta Misra 		/*
692dbed73cbSSangeeta Misra 		 * here we implement the requirement that server IDs start
693dbed73cbSSangeeta Misra 		 * with a character that is not legal in hostnames - in our
694dbed73cbSSangeeta Misra 		 * case, a "_" (underscore).
695dbed73cbSSangeeta Misra 		 */
696dbed73cbSSangeeta Misra 		(void) snprintf(srv->sgs_srvID,
697dbed73cbSSangeeta Misra 		    sizeof (srv->sgs_srvID), "%c%s.%d", ILB_SRVID_PREFIX,
698dbed73cbSSangeeta Misra 		    tmp_sg->isg_name, srv->sgs_id);
699dbed73cbSSangeeta Misra 		audit_sg_data.ed_serverid = srv->sgs_srvID;
700dbed73cbSSangeeta Misra 
701dbed73cbSSangeeta Misra 		/*
702dbed73cbSSangeeta Misra 		 * Before we update the kernel rules by adding the server,
703dbed73cbSSangeeta Misra 		 * we need to make checks and fail if any of the
704dbed73cbSSangeeta Misra 		 * following is true:
705dbed73cbSSangeeta Misra 		 *
706dbed73cbSSangeeta Misra 		 * o if the server has single port and the servergroup
707dbed73cbSSangeeta Misra 		 *   is associated to a DSR rule with a port range
708dbed73cbSSangeeta Misra 		 * o if the server has a port range and the servergroup
709dbed73cbSSangeeta Misra 		 *   is associated to a DSR rule with a port range and
710dbed73cbSSangeeta Misra 		 *   the rule's min and max port does not exactly
711dbed73cbSSangeeta Misra 		 *   match that of the server's.
712dbed73cbSSangeeta Misra 		 * o if the the server has a port range and the servergroup
713dbed73cbSSangeeta Misra 		 *   is associated to a NAT/Half-NAT rule with a port range
714dbed73cbSSangeeta Misra 		 *   and the rule's port range size does not match that
715dbed73cbSSangeeta Misra 		 *   of the server's.
716dbed73cbSSangeeta Misra 		 * o if the rule has a fixed hc port, check that this port
717dbed73cbSSangeeta Misra 		 *   is valid in the server's port specification.
718dbed73cbSSangeeta Misra 		 */
719dbed73cbSSangeeta Misra 		rc = i_check_srv2rules(&tmp_sg->isg_rulelist, srv);
720dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
721dbed73cbSSangeeta Misra 			ilbd_audit_server_event(&audit_sg_data,
722dbed73cbSSangeeta Misra 			    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
723dbed73cbSSangeeta Misra 			goto rollback;
724dbed73cbSSangeeta Misra 		}
725dbed73cbSSangeeta Misra 
726dbed73cbSSangeeta Misra 		if ((rc = i_add_srv2sg(tmp_sg, srv, &nsrv)) != ILB_STATUS_OK) {
727dbed73cbSSangeeta Misra 			ilbd_audit_server_event(&audit_sg_data,
728dbed73cbSSangeeta Misra 			    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
729dbed73cbSSangeeta Misra 			goto rollback;
730dbed73cbSSangeeta Misra 		}
731dbed73cbSSangeeta Misra 
732dbed73cbSSangeeta Misra 		rc = i_add_srv2krules(&tmp_sg->isg_rulelist, &nsrv->isv_srv,
733dbed73cbSSangeeta Misra 		    ev_port);
734dbed73cbSSangeeta Misra 		if (rc != ILB_STATUS_OK) {
735dbed73cbSSangeeta Misra 			ilbd_audit_server_event(&audit_sg_data,
736dbed73cbSSangeeta Misra 			    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
737dbed73cbSSangeeta Misra 			/*
738dbed73cbSSangeeta Misra 			 * The failure may be due to the serverid being on
739dbed73cbSSangeeta Misra 			 * hold in kernel for connection draining. But ilbd
740dbed73cbSSangeeta Misra 			 * has no way of knowing that. So we are freeing up
741dbed73cbSSangeeta Misra 			 * the serverid, and may run into the risk of
742dbed73cbSSangeeta Misra 			 * having this failure again, if we choose this
743dbed73cbSSangeeta Misra 			 * serverid  when processing the next add-server
744dbed73cbSSangeeta Misra 			 * command for this servergroup, while connection
745dbed73cbSSangeeta Misra 			 * draining is underway. We assume that the user
746*48bbca81SDaniel Hoffman 			 * will read the man page after they encounter
747dbed73cbSSangeeta Misra 			 * this failure, and learn to not add any server
748dbed73cbSSangeeta Misra 			 * to the servergroup until connection draining of
749dbed73cbSSangeeta Misra 			 * all servers in the  servergroup is complete.
750dbed73cbSSangeeta Misra 			 * XXX Need to revisit this when connection draining
751dbed73cbSSangeeta Misra 			 * is reworked
752dbed73cbSSangeeta Misra 			 */
753dbed73cbSSangeeta Misra 			list_remove(&tmp_sg->isg_srvlist, nsrv);
754dbed73cbSSangeeta Misra 			i_ilbd_free_srvID(tmp_sg, nsrv->isv_id);
755dbed73cbSSangeeta Misra 			free(nsrv);
756dbed73cbSSangeeta Misra 			tmp_sg->isg_srvcount--;
757dbed73cbSSangeeta Misra 			goto rollback;
758dbed73cbSSangeeta Misra 		}
759dbed73cbSSangeeta Misra 		if (ps != NULL) {
760dbed73cbSSangeeta Misra 			rc = ilbd_scf_add_srv(tmp_sg, nsrv);
761dbed73cbSSangeeta Misra 			if (rc != ILB_STATUS_OK) {
762dbed73cbSSangeeta Misra 				/*
763dbed73cbSSangeeta Misra 				 * The following should not fail since the
764dbed73cbSSangeeta Misra 				 * server is just added.  Just in case, we
765dbed73cbSSangeeta Misra 				 * pass in -1 as the event port to avoid
766dbed73cbSSangeeta Misra 				 * roll back in i_rem_srv_frm_krules() called
767dbed73cbSSangeeta Misra 				 * by i_delete_srv().
768dbed73cbSSangeeta Misra 				 */
769dbed73cbSSangeeta Misra 				ilbd_audit_server_event(&audit_sg_data,
770dbed73cbSSangeeta Misra 				    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
771dbed73cbSSangeeta Misra 				(void) i_delete_srv(tmp_sg, nsrv, -1);
772dbed73cbSSangeeta Misra 				break;
773dbed73cbSSangeeta Misra 			}
774dbed73cbSSangeeta Misra 		}
775dbed73cbSSangeeta Misra 	}
776dbed73cbSSangeeta Misra 
777dbed73cbSSangeeta Misra 	if (rc == ILB_STATUS_OK) {
778dbed73cbSSangeeta Misra 		ilbd_audit_server_event(&audit_sg_data,
779dbed73cbSSangeeta Misra 		    ILBD_ADD_SERVER_TO_GROUP, rc, ucredp);
780dbed73cbSSangeeta Misra 		return (rc);
781dbed73cbSSangeeta Misra 	}
782dbed73cbSSangeeta Misra 
783dbed73cbSSangeeta Misra rollback:
784dbed73cbSSangeeta Misra 	/*
785dbed73cbSSangeeta Misra 	 * If ilbd is initializing based on the SCF data and something fails,
786dbed73cbSSangeeta Misra 	 * the only choice is to transition the service to maintanence mode...
787dbed73cbSSangeeta Misra 	 */
788dbed73cbSSangeeta Misra 	if (ps == NULL) {
789dbed73cbSSangeeta Misra 		logerr("%s: failure during initialization -"
790dbed73cbSSangeeta Misra 		    " entering maintenance mode", __func__);
791dbed73cbSSangeeta Misra 		(void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE);
792dbed73cbSSangeeta Misra 		return (rc);
793dbed73cbSSangeeta Misra 	}
794dbed73cbSSangeeta Misra 
795dbed73cbSSangeeta Misra 	/*
796dbed73cbSSangeeta Misra 	 * we need to roll back all servers previous to the one
797dbed73cbSSangeeta Misra 	 * that just caused the failure
798dbed73cbSSangeeta Misra 	 */
799dbed73cbSSangeeta Misra 	for (j = i-1; j >= 0; j--) {
800dbed73cbSSangeeta Misra 		srv = &sg_info->sg_servers[j];
801dbed73cbSSangeeta Misra 
802dbed73cbSSangeeta Misra 		/* We should be able to find those servers just added. */
803dbed73cbSSangeeta Misra 		nsrv = i_find_srv(&tmp_sg->isg_srvlist, srv, MODE_SRVID);
804dbed73cbSSangeeta Misra 		assert(nsrv != NULL);
805dbed73cbSSangeeta Misra 		(void) i_delete_srv(tmp_sg, nsrv, -1);
806dbed73cbSSangeeta Misra 	}
807dbed73cbSSangeeta Misra 	return (rc);
808dbed73cbSSangeeta Misra }
809dbed73cbSSangeeta Misra 
810dbed73cbSSangeeta Misra static srch_ind_t
i_match_srvID(ilb_sg_srv_t * sg_srv,ilbd_srv_t * lsrv)811dbed73cbSSangeeta Misra i_match_srvID(ilb_sg_srv_t *sg_srv, ilbd_srv_t *lsrv)
812dbed73cbSSangeeta Misra {
813dbed73cbSSangeeta Misra 	if (strncmp(sg_srv->sgs_srvID, lsrv->isv_srvID,
814dbed73cbSSangeeta Misra 	    sizeof (sg_srv->sgs_srvID)) == 0) {
815dbed73cbSSangeeta Misra 		return (stop_found);
816dbed73cbSSangeeta Misra 	}
817dbed73cbSSangeeta Misra 	return (cont_search);
818dbed73cbSSangeeta Misra }
819dbed73cbSSangeeta Misra 
820dbed73cbSSangeeta Misra /*
821dbed73cbSSangeeta Misra  * Sanity check on a rule's port specification against all the servers'
822dbed73cbSSangeeta Misra  * specification in its associated server group.
823dbed73cbSSangeeta Misra  *
824dbed73cbSSangeeta Misra  * 1. If the health check's probe port (hcport) is specified.
825dbed73cbSSangeeta Misra  *    - if server port range is specified, check if hcport is inside
826