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 <stdio.h>
28dbed73cbSSangeeta Misra #include <strings.h>
29dbed73cbSSangeeta Misra #include <sys/types.h>
30dbed73cbSSangeeta Misra #include <sys/socket.h>
31dbed73cbSSangeeta Misra #include <netinet/in.h>
32dbed73cbSSangeeta Misra #include <arpa/inet.h>
33dbed73cbSSangeeta Misra #include <sys/list.h>
34dbed73cbSSangeeta Misra #include <libilb.h>
35dbed73cbSSangeeta Misra #include <assert.h>
36dbed73cbSSangeeta Misra #include <libscf.h>
37dbed73cbSSangeeta Misra #include "libilb_impl.h"
38dbed73cbSSangeeta Misra #include "ilbd.h"
39dbed73cbSSangeeta Misra 
40dbed73cbSSangeeta Misra #define	ILBD_PG_NAME_RULE "rule_"
41dbed73cbSSangeeta Misra #define	ILBD_PG_NAME_SG "sg_"
42dbed73cbSSangeeta Misra #define	ILBD_PG_NAME_HC "hc_"
43dbed73cbSSangeeta Misra #define	ILBD_SVC_FMRI "svc:/network/loadbalancer/ilb"
44dbed73cbSSangeeta Misra #define	ILBD_INST_NAME "default"
45dbed73cbSSangeeta Misra 
46dbed73cbSSangeeta Misra typedef enum {
47dbed73cbSSangeeta Misra 	ILBD_RULE_STATUS,
48dbed73cbSSangeeta Misra 	ILBD_RULE_VIP,
49dbed73cbSSangeeta Misra 	ILBD_RULE_PROTO,
50dbed73cbSSangeeta Misra 	ILBD_RULE_PORT,
51dbed73cbSSangeeta Misra 	ILBD_RULE_ALGO,
52dbed73cbSSangeeta Misra 	ILBD_RULE_TOPO,
53dbed73cbSSangeeta Misra 	ILBD_RULE_NAT_STR,
54dbed73cbSSangeeta Misra 	ILBD_RULE_NAT_END,
55dbed73cbSSangeeta Misra 	ILBD_RULE_STI_MASK,
56dbed73cbSSangeeta Misra 	ILBD_RULE_SGNAME,
57dbed73cbSSangeeta Misra 	ILBD_RULE_HCNAME,
58dbed73cbSSangeeta Misra 	ILBD_RULE_HCPORT,
59dbed73cbSSangeeta Misra 	ILBD_RULE_HCPFLAG,
60dbed73cbSSangeeta Misra 	ILBD_RULE_DRAINTIME,
61dbed73cbSSangeeta Misra 	ILBD_RULE_NAT_TO,
62dbed73cbSSangeeta Misra 	ILBD_RULE_PERS_TO,
63dbed73cbSSangeeta Misra 
64dbed73cbSSangeeta Misra 	ILBD_SG_SERVER,
65dbed73cbSSangeeta Misra 
66dbed73cbSSangeeta Misra 	ILBD_HC_TEST,
67dbed73cbSSangeeta Misra 	ILBD_HC_TIMEOUT,
68dbed73cbSSangeeta Misra 	ILBD_HC_INTERVAL,
69dbed73cbSSangeeta Misra 	ILBD_HC_DEF_PING,
70dbed73cbSSangeeta Misra 	ILBD_HC_COUNT,
71dbed73cbSSangeeta Misra 
72dbed73cbSSangeeta Misra 	ILBD_VAR_INVALID
73dbed73cbSSangeeta Misra } ilbd_var_type_t;
74dbed73cbSSangeeta Misra 
75dbed73cbSSangeeta Misra typedef struct prop_tbl_entry {
76dbed73cbSSangeeta Misra 	ilbd_var_type_t val_type;
77dbed73cbSSangeeta Misra 	const char *scf_propname;
78dbed73cbSSangeeta Misra 	scf_type_t scf_proptype;
79dbed73cbSSangeeta Misra } prop_tbl_entry_t;
80dbed73cbSSangeeta Misra 
81dbed73cbSSangeeta Misra /*
82dbed73cbSSangeeta Misra  * this table contains a map of all SCF properties, including rules,
83dbed73cbSSangeeta Misra  * servergroups and health checks. The place to add new property needs to be
84dbed73cbSSangeeta Misra  * watched carefully. When new properties are added, corresponding *VAR_NUM
85dbed73cbSSangeeta Misra  * needs to be adjusted to reflect the correct index of the table
86dbed73cbSSangeeta Misra  */
87dbed73cbSSangeeta Misra prop_tbl_entry_t prop_tbl[] = {
88dbed73cbSSangeeta Misra 	/* entried for rule */
89dbed73cbSSangeeta Misra 	{ILBD_RULE_STATUS, "status", SCF_TYPE_BOOLEAN},
90dbed73cbSSangeeta Misra 	/* SCF_TYPE_NET_ADDR_V4 or SCF_TYPE_NET_ADDR_V6 */
91dbed73cbSSangeeta Misra 	{ILBD_RULE_VIP, "vip", SCF_TYPE_INVALID},
92dbed73cbSSangeeta Misra 	{ILBD_RULE_PROTO, "protocol", SCF_TYPE_ASTRING},
93dbed73cbSSangeeta Misra 	{ILBD_RULE_PORT, "port", SCF_TYPE_ASTRING},
94dbed73cbSSangeeta Misra 	{ILBD_RULE_ALGO, "ilb-algo", SCF_TYPE_ASTRING},
95dbed73cbSSangeeta Misra 	{ILBD_RULE_TOPO, "ilb-type", SCF_TYPE_ASTRING},
96dbed73cbSSangeeta Misra 	{ILBD_RULE_NAT_STR, "ilb-nat-start", SCF_TYPE_INVALID},
97dbed73cbSSangeeta Misra 	{ILBD_RULE_NAT_END, "ilb-nat-end", SCF_TYPE_INVALID},
98dbed73cbSSangeeta Misra 	{ILBD_RULE_STI_MASK, "ilb-sti-mask", SCF_TYPE_INVALID},
99dbed73cbSSangeeta Misra 	{ILBD_RULE_SGNAME, "servergroup", SCF_TYPE_ASTRING},
100dbed73cbSSangeeta Misra 	{ILBD_RULE_HCNAME, "healthcheck", SCF_TYPE_ASTRING},
101dbed73cbSSangeeta Misra 	{ILBD_RULE_HCPORT, "hc-port", SCF_TYPE_INTEGER},
102dbed73cbSSangeeta Misra 	{ILBD_RULE_HCPFLAG, "hcp-flag", SCF_TYPE_INTEGER},
103dbed73cbSSangeeta Misra 	{ILBD_RULE_DRAINTIME, "drain-time", SCF_TYPE_INTEGER},
104dbed73cbSSangeeta Misra 	{ILBD_RULE_NAT_TO, "nat-timeout", SCF_TYPE_INTEGER},
105dbed73cbSSangeeta Misra 	{ILBD_RULE_PERS_TO, "pers-timeout", SCF_TYPE_INTEGER},
106dbed73cbSSangeeta Misra 	/* add new rule related prop here */
107dbed73cbSSangeeta Misra 	/* entries for sg */
108dbed73cbSSangeeta Misra 	{ILBD_SG_SERVER, "server", SCF_TYPE_ASTRING},
109dbed73cbSSangeeta Misra 	/* add new sg related prop here */
110dbed73cbSSangeeta Misra 	/* entries for hc */
111dbed73cbSSangeeta Misra 	{ILBD_HC_TEST, "test", SCF_TYPE_ASTRING},
112dbed73cbSSangeeta Misra 	{ILBD_HC_TIMEOUT, "timeout", SCF_TYPE_INTEGER},
113dbed73cbSSangeeta Misra 	{ILBD_HC_INTERVAL, "interval", SCF_TYPE_INTEGER},
114dbed73cbSSangeeta Misra 	{ILBD_HC_DEF_PING, "ping", SCF_TYPE_BOOLEAN},
115dbed73cbSSangeeta Misra 	/* add new hc related prop here */
116dbed73cbSSangeeta Misra 	{ILBD_HC_COUNT, "count", SCF_TYPE_INTEGER}
117dbed73cbSSangeeta Misra };
118dbed73cbSSangeeta Misra 
119dbed73cbSSangeeta Misra #define	ILBD_PROP_VAR_NUM (ILBD_HC_COUNT + 1)
120dbed73cbSSangeeta Misra #define	ILBD_RULE_VAR_NUM (ILBD_SG_SERVER)
121dbed73cbSSangeeta Misra #define	ILBD_SG_VAR_NUM (ILBD_HC_TEST - ILBD_SG_SERVER)
122dbed73cbSSangeeta Misra #define	ILBD_HC_VAR_NUM (ILBD_PROP_VAR_NUM - ILBD_HC_TEST)
123dbed73cbSSangeeta Misra 
124dbed73cbSSangeeta Misra static ilb_status_t ilbd_scf_set_prop(scf_propertygroup_t *, const char *,
125dbed73cbSSangeeta Misra     scf_type_t, scf_value_t *);
126dbed73cbSSangeeta Misra static ilb_status_t ilbd_scf_retrieve_pg(const char *, scf_propertygroup_t **,
127dbed73cbSSangeeta Misra     boolean_t);
128dbed73cbSSangeeta Misra static ilb_status_t ilbd_scf_delete_pg(scf_propertygroup_t *);
129dbed73cbSSangeeta Misra static ilb_status_t ilbd_scf_get_prop_val(scf_propertygroup_t *, const char *,
130dbed73cbSSangeeta Misra     scf_value_t **);
131dbed73cbSSangeeta Misra 
132dbed73cbSSangeeta Misra #define	MIN(a, b)	((a) < (b) ? (a) : (b))
133dbed73cbSSangeeta Misra 
134dbed73cbSSangeeta Misra int
ilbd_scf_limit(int type)135dbed73cbSSangeeta Misra ilbd_scf_limit(int type)
136dbed73cbSSangeeta Misra {
137dbed73cbSSangeeta Misra 	return (MIN(scf_limit(type), 120));
138dbed73cbSSangeeta Misra }
139dbed73cbSSangeeta Misra 
140dbed73cbSSangeeta Misra /*
141dbed73cbSSangeeta Misra  * Translate libscf error to libilb status
142dbed73cbSSangeeta Misra  */
143dbed73cbSSangeeta Misra ilb_status_t
ilbd_scf_err_to_ilb_err()144dbed73cbSSangeeta Misra ilbd_scf_err_to_ilb_err()
145dbed73cbSSangeeta Misra {
146dbed73cbSSangeeta Misra 	switch (scf_error()) {
147dbed73cbSSangeeta Misra 	case SCF_ERROR_NONE:
148dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
149dbed73cbSSangeeta Misra 	case SCF_ERROR_HANDLE_MISMATCH:
150dbed73cbSSangeeta Misra 	case SCF_ERROR_HANDLE_DESTROYED:
151dbed73cbSSangeeta Misra 	case SCF_ERROR_VERSION_MISMATCH:
152dbed73cbSSangeeta Misra 	case SCF_ERROR_NOT_BOUND:
153dbed73cbSSangeeta Misra 	case SCF_ERROR_CONSTRAINT_VIOLATED:
154dbed73cbSSangeeta Misra 	case SCF_ERROR_NOT_SET:
155dbed73cbSSangeeta Misra 	case SCF_ERROR_TYPE_MISMATCH:
156dbed73cbSSangeeta Misra 	case SCF_ERROR_INVALID_ARGUMENT:
157dbed73cbSSangeeta Misra 		return (ILB_STATUS_EINVAL);
158dbed73cbSSangeeta Misra 	case SCF_ERROR_NO_MEMORY:
159dbed73cbSSangeeta Misra 	case SCF_ERROR_NO_RESOURCES:
160dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
161dbed73cbSSangeeta Misra 	case SCF_ERROR_NOT_FOUND:
162dbed73cbSSangeeta Misra 	case SCF_ERROR_DELETED:
163dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
164dbed73cbSSangeeta Misra 	case SCF_ERROR_EXISTS:
165dbed73cbSSangeeta Misra 		return (ILB_STATUS_EEXIST);
166dbed73cbSSangeeta Misra 	case SCF_ERROR_PERMISSION_DENIED:
167dbed73cbSSangeeta Misra 		return (ILB_STATUS_PERMIT);
168dbed73cbSSangeeta Misra 	case SCF_ERROR_CALLBACK_FAILED:
169dbed73cbSSangeeta Misra 		return (ILB_STATUS_CALLBACK);
170dbed73cbSSangeeta Misra 	case SCF_ERROR_IN_USE:
171dbed73cbSSangeeta Misra 		return (ILB_STATUS_INUSE);
172dbed73cbSSangeeta Misra 	default:
173dbed73cbSSangeeta Misra 		return (ILB_STATUS_INTERNAL);
174dbed73cbSSangeeta Misra 	}
175dbed73cbSSangeeta Misra }
176dbed73cbSSangeeta Misra 
177dbed73cbSSangeeta Misra static void
ilbd_name_to_scfpgname(ilbd_scf_pg_type_t pg_type,const char * pgname,char * scf_pgname)178dbed73cbSSangeeta Misra ilbd_name_to_scfpgname(ilbd_scf_pg_type_t pg_type, const char *pgname,
179dbed73cbSSangeeta Misra     char *scf_pgname)
180dbed73cbSSangeeta Misra {
181dbed73cbSSangeeta Misra 	switch (pg_type) {
182dbed73cbSSangeeta Misra 	case ILBD_SCF_RULE:
183dbed73cbSSangeeta Misra 		(void) snprintf(scf_pgname, ILBD_MAX_NAME_LEN,
184dbed73cbSSangeeta Misra 		    ILBD_PG_NAME_RULE "%s", pgname);
185dbed73cbSSangeeta Misra 		return;
186dbed73cbSSangeeta Misra 	case ILBD_SCF_SG:
187dbed73cbSSangeeta Misra 		(void) snprintf(scf_pgname, ILBD_MAX_NAME_LEN,
188dbed73cbSSangeeta Misra 		    ILBD_PG_NAME_SG "%s", pgname);
189dbed73cbSSangeeta Misra 		return;
190dbed73cbSSangeeta Misra 	case ILBD_SCF_HC:
191dbed73cbSSangeeta Misra 		(void) snprintf(scf_pgname, ILBD_MAX_NAME_LEN,
192dbed73cbSSangeeta Misra 		    ILBD_PG_NAME_HC "%s", pgname);
193dbed73cbSSangeeta Misra 		return;
194dbed73cbSSangeeta Misra 	/* Should not happen.  Log it and put ILB service in maintenance. */
195dbed73cbSSangeeta Misra 	default:
196dbed73cbSSangeeta Misra 		logerr("ilbd_name_to_scfpgname: invalid pg type %d for pg %s",
197dbed73cbSSangeeta Misra 		    pg_type, pgname);
198dbed73cbSSangeeta Misra 		(void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE);
199dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
200dbed73cbSSangeeta Misra 		return;
201dbed73cbSSangeeta Misra 	}
202dbed73cbSSangeeta Misra }
203dbed73cbSSangeeta Misra 
204dbed73cbSSangeeta Misra static void
ilbd_scf_destroy(scf_handle_t * h,scf_service_t * s,scf_instance_t * inst,scf_propertygroup_t * pg)205dbed73cbSSangeeta Misra ilbd_scf_destroy(scf_handle_t *h, scf_service_t *s, scf_instance_t *inst,
206dbed73cbSSangeeta Misra     scf_propertygroup_t *pg)
207dbed73cbSSangeeta Misra {
208dbed73cbSSangeeta Misra 	if (pg != NULL)
209dbed73cbSSangeeta Misra 		scf_pg_destroy(pg);
210dbed73cbSSangeeta Misra 	if (inst != NULL)
211dbed73cbSSangeeta Misra 		scf_instance_destroy(inst);
212dbed73cbSSangeeta Misra 	if (s != NULL)
213dbed73cbSSangeeta Misra 		scf_service_destroy(s);
214dbed73cbSSangeeta Misra 	if (h != NULL)
215dbed73cbSSangeeta Misra 		scf_handle_destroy(h);
216dbed73cbSSangeeta Misra }
217dbed73cbSSangeeta Misra 
218dbed73cbSSangeeta Misra 
219dbed73cbSSangeeta Misra static ilb_status_t
ilbd_scf_get_inst(scf_handle_t ** h,scf_service_t ** svc,scf_instance_t ** inst)220dbed73cbSSangeeta Misra ilbd_scf_get_inst(scf_handle_t **h, scf_service_t **svc, scf_instance_t **inst)
221dbed73cbSSangeeta Misra {
222dbed73cbSSangeeta Misra 	if ((*h = scf_handle_create(SCF_VERSION)) == NULL)
223dbed73cbSSangeeta Misra 		return (ILB_STATUS_INTERNAL);
224dbed73cbSSangeeta Misra 
225dbed73cbSSangeeta Misra 	if (scf_handle_bind(*h) != 0) {
226dbed73cbSSangeeta Misra 		ilbd_scf_destroy(*h, NULL, NULL, NULL);
227dbed73cbSSangeeta Misra 		return (ilbd_scf_err_to_ilb_err());
228dbed73cbSSangeeta Misra 	}
229dbed73cbSSangeeta Misra 
230dbed73cbSSangeeta Misra 	if ((*svc = scf_service_create(*h)) == NULL) {
231dbed73cbSSangeeta Misra 		ilbd_scf_destroy(*h, NULL, NULL, NULL);
232dbed73cbSSangeeta Misra 		return (ilbd_scf_err_to_ilb_err());
233dbed73cbSSangeeta Misra 	}
234dbed73cbSSangeeta Misra 
235dbed73cbSSangeeta Misra 	if (scf_handle_decode_fmri(*h, ILBD_SVC_FMRI, NULL, *svc, NULL, NULL,
236dbed73cbSSangeeta Misra 	    NULL, SCF_DECODE_FMRI_EXACT) != 0) {
237dbed73cbSSangeeta Misra 		ilbd_scf_destroy(*h, *svc, NULL, NULL);
238dbed73cbSSangeeta Misra 		return (ilbd_scf_err_to_ilb_err());
239dbed73cbSSangeeta Misra 	}
240dbed73cbSSangeeta Misra 
241dbed73cbSSangeeta Misra 	if ((*inst = scf_instance_create(*h)) == NULL) {
242dbed73cbSSangeeta Misra 		ilbd_scf_destroy(*h, *svc, NULL, NULL);
243dbed73cbSSangeeta Misra 		return (ilbd_scf_err_to_ilb_err());
244dbed73cbSSangeeta Misra 	}
245dbed73cbSSangeeta Misra 
246dbed73cbSSangeeta Misra 	if (scf_service_get_instance(*svc, ILBD_INST_NAME, *inst) != 0) {
247dbed73cbSSangeeta Misra 		ilbd_scf_destroy(*h, *svc, *inst, NULL);
248dbed73cbSSangeeta Misra 		return (ilbd_scf_err_to_ilb_err());
249dbed73cbSSangeeta Misra 	}
250dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
251dbed73cbSSangeeta Misra }
252dbed73cbSSangeeta Misra 
253dbed73cbSSangeeta Misra /*
254dbed73cbSSangeeta Misra  * If create is set, create a new prop group, destroy the old one if exists.
255dbed73cbSSangeeta Misra  * If create not set, try to find the prop group with given name.
256dbed73cbSSangeeta Misra  * The created or found entry is returned as *pg.
257dbed73cbSSangeeta Misra  * Caller frees *pg and its handle scf_pg_handle(pg)
258dbed73cbSSangeeta Misra  */
259dbed73cbSSangeeta Misra static ilb_status_t
ilbd_scf_retrieve_pg(const char * pgname,scf_propertygroup_t ** pg,boolean_t create)260dbed73cbSSangeeta Misra ilbd_scf_retrieve_pg(const char *pgname, scf_propertygroup_t **pg,
261dbed73cbSSangeeta Misra     boolean_t create)
262dbed73cbSSangeeta Misra {
263dbed73cbSSangeeta Misra 	scf_instance_t *inst;
264dbed73cbSSangeeta Misra 	scf_handle_t *h;
265dbed73cbSSangeeta Misra 	scf_service_t *svc;
266dbed73cbSSangeeta Misra 	ilb_status_t ret;
267dbed73cbSSangeeta Misra 
268dbed73cbSSangeeta Misra 	ret = ilbd_scf_get_inst(&h, &svc, &inst);
269dbed73cbSSangeeta Misra 	if (ret != ILB_STATUS_OK)
270dbed73cbSSangeeta Misra 		return (ret);
271dbed73cbSSangeeta Misra 
272dbed73cbSSangeeta Misra 	*pg = scf_pg_create(h);
273dbed73cbSSangeeta Misra 	if (*pg == NULL)
274dbed73cbSSangeeta Misra 		return (ILB_STATUS_INTERNAL);
275dbed73cbSSangeeta Misra 
276dbed73cbSSangeeta Misra 	if (scf_instance_get_pg(inst, pgname, *pg) != 0) {
277dbed73cbSSangeeta Misra 		if (scf_error() != SCF_ERROR_NOT_FOUND ||
278dbed73cbSSangeeta Misra 		    (scf_error() == SCF_ERROR_NOT_FOUND && (!create))) {
279dbed73cbSSangeeta Misra 			ilbd_scf_destroy(h, svc, inst, *pg);
280dbed73cbSSangeeta Misra 			*pg = NULL;
281dbed73cbSSangeeta Misra 			return (ilbd_scf_err_to_ilb_err());
282dbed73cbSSangeeta Misra 		}
283dbed73cbSSangeeta Misra 	} else {
284dbed73cbSSangeeta Misra 		/*
285dbed73cbSSangeeta Misra 		 * Found pg, don't want to create, return EEXIST.  Note that
286dbed73cbSSangeeta Misra 		 * h cannot be destroyed here since the caller needs to use it.
287dbed73cbSSangeeta Misra 		 * The caller gets it by calling scf_pg_handle().
288dbed73cbSSangeeta Misra 		 */
289dbed73cbSSangeeta Misra 		if (!create) {
290dbed73cbSSangeeta Misra 			ilbd_scf_destroy(NULL, svc, inst, NULL);
291dbed73cbSSangeeta Misra 			return (ILB_STATUS_EEXIST);
292dbed73cbSSangeeta Misra 		}
293dbed73cbSSangeeta Misra 		/* found pg, need to create, destroy the existing one */
294dbed73cbSSangeeta Misra 		else
295dbed73cbSSangeeta Misra 			(void) ilbd_scf_delete_pg(*pg);
296dbed73cbSSangeeta Misra 	}
297dbed73cbSSangeeta Misra 
298dbed73cbSSangeeta Misra 	if (create) {
299dbed73cbSSangeeta Misra 		if (scf_instance_add_pg(inst, pgname,
300dbed73cbSSangeeta Misra 		    SCF_GROUP_APPLICATION, 0, *pg) != 0) {
301dbed73cbSSangeeta Misra 			ilbd_scf_destroy(h, svc, inst, *pg);
302dbed73cbSSangeeta Misra 			*pg = NULL;
303dbed73cbSSangeeta Misra 			return (ilbd_scf_err_to_ilb_err());
304dbed73cbSSangeeta Misra 		}
305dbed73cbSSangeeta Misra 	}
306dbed73cbSSangeeta Misra 
307dbed73cbSSangeeta Misra 	/*
308dbed73cbSSangeeta Misra 	 * Note that handle cannot be destroyed here, caller sometimes needs
309dbed73cbSSangeeta Misra 	 * to use it.  It gets the handle by calling scf_pg_handle().
310dbed73cbSSangeeta Misra 	 */
311dbed73cbSSangeeta Misra 	ilbd_scf_destroy(NULL, svc, inst, NULL);
312dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
313dbed73cbSSangeeta Misra }
314dbed73cbSSangeeta Misra 
315dbed73cbSSangeeta Misra struct algo_tbl_entry {
316dbed73cbSSangeeta Misra 	ilb_algo_t algo_type;
317dbed73cbSSangeeta Misra 	const char *algo_str;
318dbed73cbSSangeeta Misra } algo_tbl[] = {
319dbed73cbSSangeeta Misra 	{ILB_ALG_ROUNDROBIN, "ROUNDROBIN"},
320dbed73cbSSangeeta Misra 	{ILB_ALG_HASH_IP, "HASH-IP"},
321dbed73cbSSangeeta Misra 	{ILB_ALG_HASH_IP_SPORT, "HASH-IP-PORT"},
322dbed73cbSSangeeta Misra 	{ILB_ALG_HASH_IP_VIP, "HASH-IP-VIP"}
323dbed73cbSSangeeta Misra };
324dbed73cbSSangeeta Misra 
325dbed73cbSSangeeta Misra #define	ILBD_ALGO_TBL_SIZE (sizeof (algo_tbl) / \
326dbed73cbSSangeeta Misra 	sizeof (*algo_tbl))
327dbed73cbSSangeeta Misra 
328dbed73cbSSangeeta Misra void
ilbd_algo_to_str(ilb_algo_t algo_type,char * valstr)329dbed73cbSSangeeta Misra ilbd_algo_to_str(ilb_algo_t algo_type, char *valstr)
330dbed73cbSSangeeta Misra {
331dbed73cbSSangeeta Misra 	int i;
332dbed73cbSSangeeta Misra 
333dbed73cbSSangeeta Misra 	for (i = 0; i < ILBD_ALGO_TBL_SIZE; i++) {
334dbed73cbSSangeeta Misra 		if (algo_type == algo_tbl[i].algo_type) {
335dbed73cbSSangeeta Misra 			(void) strlcpy(valstr, algo_tbl[i].algo_str,
336dbed73cbSSangeeta Misra 			    ILBD_MAX_VALUE_LEN);
337dbed73cbSSangeeta Misra 			return;
338dbed73cbSSangeeta Misra 		}
339dbed73cbSSangeeta Misra 	}
340dbed73cbSSangeeta Misra 	logerr("ilbd_algo_to_str: algo not found");
341dbed73cbSSangeeta Misra }
342dbed73cbSSangeeta Misra 
343dbed73cbSSangeeta Misra static void
ilbd_scf_str_to_algo(ilb_algo_t * algo_type,char * valstr)344dbed73cbSSangeeta Misra ilbd_scf_str_to_algo(ilb_algo_t *algo_type, char *valstr)
345dbed73cbSSangeeta Misra {
346dbed73cbSSangeeta Misra 	int i;
347dbed73cbSSangeeta Misra 
348dbed73cbSSangeeta Misra 	for (i = 0; i < ILBD_ALGO_TBL_SIZE; i++) {
349dbed73cbSSangeeta Misra 		if (strcmp(valstr, algo_tbl[i].algo_str) == 0) {
350dbed73cbSSangeeta Misra 			*algo_type = algo_tbl[i].algo_type;
351dbed73cbSSangeeta Misra 			return;
352dbed73cbSSangeeta Misra 		}
353dbed73cbSSangeeta Misra 	}
354dbed73cbSSangeeta Misra 	logerr("ilbd_scf_str_to_algo: algo not found");
355dbed73cbSSangeeta Misra }
356dbed73cbSSangeeta Misra 
357dbed73cbSSangeeta Misra struct topo_tbl_entry {
358dbed73cbSSangeeta Misra 	ilb_topo_t topo_type;
359dbed73cbSSangeeta Misra 	const char *topo_str;
360dbed73cbSSangeeta Misra } topo_tbl[] = {
361dbed73cbSSangeeta Misra 	{ILB_TOPO_DSR, "DSR"},
362dbed73cbSSangeeta Misra 	{ILB_TOPO_NAT, "NAT"},
363dbed73cbSSangeeta Misra 	{ILB_TOPO_HALF_NAT, "HALF-NAT"}
364dbed73cbSSangeeta Misra };
365dbed73cbSSangeeta Misra 
366dbed73cbSSangeeta Misra #define	ILBD_TOPO_TBL_SIZE (sizeof (topo_tbl) / \
367dbed73cbSSangeeta Misra 	sizeof (*topo_tbl))
368dbed73cbSSangeeta Misra 
369dbed73cbSSangeeta Misra void
ilbd_topo_to_str(ilb_topo_t topo_type,char * valstr)370dbed73cbSSangeeta Misra ilbd_topo_to_str(ilb_topo_t topo_type, char *valstr)
371dbed73cbSSangeeta Misra {
372dbed73cbSSangeeta Misra 	int i;
373dbed73cbSSangeeta Misra 
374dbed73cbSSangeeta Misra 	for (i = 0; i < ILBD_TOPO_TBL_SIZE; i++) {
375dbed73cbSSangeeta Misra 		if (topo_type == topo_tbl[i].topo_type) {
376dbed73cbSSangeeta Misra 			(void) strlcpy(valstr, topo_tbl[i].topo_str,
377dbed73cbSSangeeta Misra 			    ILBD_MAX_VALUE_LEN);
378dbed73cbSSangeeta Misra 			return;
379dbed73cbSSangeeta Misra 		}
380dbed73cbSSangeeta Misra 	}
381dbed73cbSSangeeta Misra 	logerr("ilbd_scf_topo_to_str: topo not found");
382dbed73cbSSangeeta Misra }
383dbed73cbSSangeeta Misra 
384dbed73cbSSangeeta Misra static void
ilbd_scf_str_to_topo(ilb_topo_t * topo_type,char * valstr)385dbed73cbSSangeeta Misra ilbd_scf_str_to_topo(ilb_topo_t *topo_type, char *valstr)
386dbed73cbSSangeeta Misra {
387dbed73cbSSangeeta Misra 	int i;
388dbed73cbSSangeeta Misra 
389dbed73cbSSangeeta Misra 	for (i = 0; i < ILBD_TOPO_TBL_SIZE; i++) {
390dbed73cbSSangeeta Misra 		if (strcmp(valstr, topo_tbl[i].topo_str) == 0) {
391dbed73cbSSangeeta Misra 			*topo_type = topo_tbl[i].topo_type;
392dbed73cbSSangeeta Misra 			return;
393dbed73cbSSangeeta Misra 		}
394dbed73cbSSangeeta Misra 	}
395dbed73cbSSangeeta Misra 	logerr("ilbd_scf_str_to_topo: topo not found");
396dbed73cbSSangeeta Misra }
397dbed73cbSSangeeta Misra 
398dbed73cbSSangeeta Misra static void
ilbd_get_svr_field(char * valstr,struct in6_addr * sgs_addr,int32_t * min_port,int32_t * max_port,int32_t * sgs_flags)399dbed73cbSSangeeta Misra ilbd_get_svr_field(char *valstr, struct in6_addr *sgs_addr,
400dbed73cbSSangeeta Misra     int32_t *min_port, int32_t *max_port, int32_t *sgs_flags)
401dbed73cbSSangeeta Misra {
402dbed73cbSSangeeta Misra 	char *ipaddr, *ipverstr, *portstr, *flagstr;
403dbed73cbSSangeeta Misra 	int ip_ver;
404dbed73cbSSangeeta Misra 	ilb_ip_addr_t temp_ip;
405dbed73cbSSangeeta Misra 	void *addrptr;
406dbed73cbSSangeeta Misra 	char *max_portstr;
407dbed73cbSSangeeta Misra 
408dbed73cbSSangeeta Misra 	ipaddr = strtok(valstr, ";");
409dbed73cbSSangeeta Misra 	ipverstr = strtok(NULL, ";");
410dbed73cbSSangeeta Misra 	portstr = strtok(NULL, ";");
411dbed73cbSSangeeta Misra 	flagstr = strtok(NULL, ";");
412dbed73cbSSangeeta Misra 
413dbed73cbSSangeeta Misra 	if (ipaddr == NULL || ipverstr == NULL || portstr == NULL ||
414dbed73cbSSangeeta Misra 	    flagstr == NULL) {
415dbed73cbSSangeeta Misra 		logerr("%s: invalid server fields", __func__);
416dbed73cbSSangeeta Misra 		(void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE);
417dbed73cbSSangeeta Misra 		exit(EXIT_FAILURE);
418dbed73cbSSangeeta Misra 	}
419dbed73cbSSangeeta Misra 	ip_ver = atoi(ipverstr);
420dbed73cbSSangeeta Misra 	addrptr = (ip_ver == AF_INET) ? (void *)&temp_ip.ia_v4 :
421dbed73cbSSangeeta Misra 	    (void *)&temp_ip.ia_v6;
422*95c74518SToomas Soome 	if (inet_pton(ip_ver, ipaddr, addrptr) == 0) {
423dbed73cbSSangeeta Misra 		logerr("ilbd_get_svr_field: inet_pton failed");
424dbed73cbSSangeeta Misra 		return;
425dbed73cbSSangeeta Misra 	}
426dbed73cbSSangeeta Misra 
427dbed73cbSSangeeta Misra 	if (ip_ver == AF_INET) {
428dbed73cbSSangeeta Misra 		IN6_INADDR_TO_V4MAPPED(&(temp_ip.ia_v4), sgs_addr);
429dbed73cbSSangeeta Misra 	} else {
430dbed73cbSSangeeta Misra 		(void) memcpy(sgs_addr, &(temp_ip.ia_v6),
431dbed73cbSSangeeta Misra 		    sizeof (struct in6_addr));
432dbed73cbSSangeeta Misra 	}
433dbed73cbSSangeeta Misra 
434dbed73cbSSangeeta Misra 	*sgs_flags = atoi(flagstr);
435dbed73cbSSangeeta Misra 	*min_port = atoi(strtok(portstr, "-"));
436dbed73cbSSangeeta Misra 	*min_port = ntohs(*min_port);
437dbed73cbSSangeeta Misra 	max_portstr = strtok(NULL, "-");
438dbed73cbSSangeeta Misra 	if (max_portstr != NULL) {
439dbed73cbSSangeeta Misra 		*max_port = atoi(max_portstr);
440dbed73cbSSangeeta Misra 		*max_port = ntohs(*max_port);
441dbed73cbSSangeeta Misra 	}
442dbed73cbSSangeeta Misra }
443dbed73cbSSangeeta Misra 
444dbed73cbSSangeeta Misra /*
445dbed73cbSSangeeta Misra  * Convert the info of a server to its SCF string value representation.
446dbed73cbSSangeeta Misra  * Argument value is assumed to be of size ILBD_MAX_VALUE_LEN.
447dbed73cbSSangeeta Misra  */
448dbed73cbSSangeeta Misra static void
ilbd_srv_scf_val(ilbd_srv_t * srv,char * value)449dbed73cbSSangeeta Misra ilbd_srv_scf_val(ilbd_srv_t *srv, char *value)
450dbed73cbSSangeeta Misra {
451dbed73cbSSangeeta Misra 	char ipstr[INET6_ADDRSTRLEN];
452dbed73cbSSangeeta Misra 	int ipver;
453dbed73cbSSangeeta Misra 
454dbed73cbSSangeeta Misra 	if (GET_AF(&srv->isv_addr) == AF_INET) {
455dbed73cbSSangeeta Misra 		struct in_addr v4_addr;
456dbed73cbSSangeeta Misra 
457dbed73cbSSangeeta Misra 		IN6_V4MAPPED_TO_INADDR(&srv->isv_addr, &v4_addr);
458dbed73cbSSangeeta Misra 		(void) inet_ntop(AF_INET, &v4_addr, ipstr, sizeof (ipstr));
459dbed73cbSSangeeta Misra 		ipver = AF_INET;
460dbed73cbSSangeeta Misra 	} else {
461dbed73cbSSangeeta Misra 		(void) inet_ntop(AF_INET6, &srv->isv_addr, ipstr,
462dbed73cbSSangeeta Misra 		    sizeof (ipstr));
463dbed73cbSSangeeta Misra 		ipver = AF_INET6;
464dbed73cbSSangeeta Misra 	}
465dbed73cbSSangeeta Misra 	(void) snprintf(value, ILBD_MAX_VALUE_LEN, "%s;%d;%d-%d;%d",
466dbed73cbSSangeeta Misra 	    ipstr, ipver, ntohs(srv->isv_minport), ntohs(srv->isv_maxport),
467dbed73cbSSangeeta Misra 	    srv->isv_flags);
468dbed73cbSSangeeta Misra }
469dbed73cbSSangeeta Misra 
470dbed73cbSSangeeta Misra /* get the "ip:port:status" str of the #num server in the servergroup */
471dbed73cbSSangeeta Misra ilb_status_t
ilbd_get_svr_info(ilbd_sg_t * sg,int num,char * valstr,char * svrname)472dbed73cbSSangeeta Misra ilbd_get_svr_info(ilbd_sg_t *sg, int num, char *valstr, char *svrname)
473dbed73cbSSangeeta Misra {
474dbed73cbSSangeeta Misra 	int i;
475dbed73cbSSangeeta Misra 	ilbd_srv_t *tmp_srv = NULL;
476dbed73cbSSangeeta Misra 
477dbed73cbSSangeeta Misra 	tmp_srv = list_head(&sg->isg_srvlist);
478dbed73cbSSangeeta Misra 	if (tmp_srv == NULL)
479dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOENT);
480dbed73cbSSangeeta Misra 
481dbed73cbSSangeeta Misra 	for (i = 0; i < num; i++)
482dbed73cbSSangeeta Misra 		tmp_srv = list_next(&sg->isg_srvlist, tmp_srv);
483dbed73cbSSangeeta Misra 
484dbed73cbSSangeeta Misra 	assert(tmp_srv != NULL);
485dbed73cbSSangeeta Misra 	if (valstr != NULL)
486dbed73cbSSangeeta Misra 		ilbd_srv_scf_val(tmp_srv, valstr);
487dbed73cbSSangeeta Misra 
488dbed73cbSSangeeta Misra 	if (svrname != NULL) {
489dbed73cbSSangeeta Misra 		(void) snprintf(svrname, ILBD_MAX_NAME_LEN, "server%d",
490dbed73cbSSangeeta Misra 		    tmp_srv->isv_id);
491dbed73cbSSangeeta Misra 	}
492dbed73cbSSangeeta Misra 
493dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
494dbed73cbSSangeeta Misra }
495dbed73cbSSangeeta Misra 
496dbed73cbSSangeeta Misra /* convert a struct in6_addr to valstr */
497dbed73cbSSangeeta Misra ilb_status_t
ilbd_scf_ip_to_str(uint16_t ipversion,struct in6_addr * addr,scf_type_t * scftype,char * valstr)498dbed73cbSSangeeta Misra ilbd_scf_ip_to_str(uint16_t ipversion, struct in6_addr *addr,
499dbed73cbSSangeeta Misra     scf_type_t *scftype, char *valstr)
500dbed73cbSSangeeta Misra {
501dbed73cbSSangeeta Misra 	size_t vallen;
502dbed73cbSSangeeta Misra 	ilb_ip_addr_t ipaddr;
503dbed73cbSSangeeta Misra 	void *addrptr;
504dbed73cbSSangeeta Misra 
505dbed73cbSSangeeta Misra 	vallen = (ipversion == AF_INET) ? INET_ADDRSTRLEN :
506dbed73cbSSangeeta Misra 	    INET6_ADDRSTRLEN;
507dbed73cbSSangeeta Misra 	if (scftype != NULL)
508dbed73cbSSangeeta Misra 		*scftype = (ipversion == AF_INET) ? SCF_TYPE_NET_ADDR_V4 :
509dbed73cbSSangeeta Misra 		    SCF_TYPE_NET_ADDR_V6;
510dbed73cbSSangeeta Misra 
511dbed73cbSSangeeta Misra 	IP_COPY_IMPL_2_CLI(addr, &ipaddr);
512dbed73cbSSangeeta Misra 	addrptr = (ipversion == AF_INET) ?
513dbed73cbSSangeeta Misra 	    (void *)&ipaddr.ia_v4 : (void *)&ipaddr.ia_v6;
514dbed73cbSSangeeta Misra 	(void) inet_ntop(ipversion, (void *)addrptr, valstr, vallen);
515dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
516dbed73cbSSangeeta Misra }
517dbed73cbSSangeeta Misra 
518dbed73cbSSangeeta Misra /*
519dbed73cbSSangeeta Misra  * This function takes a ilbd internal data struct and translate its value to
520dbed73cbSSangeeta Misra  * scf value. The data struct is passed in within "data".
521dbed73cbSSangeeta Misra  * Upon successful return, the scf val will be stored in "val" and the scf type
522dbed73cbSSangeeta Misra  * will be returned in "scftype" if scftype != NULL, the number of values
523dbed73cbSSangeeta Misra  * translated will be in "numval"
524dbed73cbSSangeeta Misra  * If it failed, no data will be written to SCF
525dbed73cbSSangeeta Misra  */
526dbed73cbSSangeeta Misra static ilb_status_t
ilbd_data_to_scfval(ilbd_scf_pg_type_t pg_type,ilbd_var_type_t type,scf_handle_t * h,void * data,scf_value_t *** val,scf_type_t * scftype,int * numval)527dbed73cbSSangeeta Misra ilbd_data_to_scfval(ilbd_scf_pg_type_t pg_type, ilbd_var_type_t type,
528dbed73cbSSangeeta Misra     scf_handle_t *h, void *data, scf_value_t ***val, scf_type_t *scftype,
529dbed73cbSSangeeta Misra     int *numval)
530dbed73cbSSangeeta Misra {
531dbed73cbSSangeeta Misra 	scf_value_t *v, **varray = NULL;
532dbed73cbSSangeeta Misra 	int ret = ILB_STATUS_OK;
533dbed73cbSSangeeta Misra 	int i;
534dbed73cbSSangeeta Misra 	int scf_val_len = ILBD_MAX_VALUE_LEN;
5353ae6a67dSSangeeta Misra 	char *valstr = NULL;
536dbed73cbSSangeeta Misra 	int valint;
537dbed73cbSSangeeta Misra 	uint8_t valbool = 0;
538dbed73cbSSangeeta Misra 	ilbd_rule_t *r_ent = NULL;
539dbed73cbSSangeeta Misra 	ilbd_sg_t *s_ent = NULL;
540dbed73cbSSangeeta Misra 	ilbd_hc_t *h_ent = NULL;
541dbed73cbSSangeeta Misra 
542dbed73cbSSangeeta Misra 	switch (pg_type) {
543dbed73cbSSangeeta Misra 	case ILBD_SCF_RULE:
544dbed73cbSSangeeta Misra 		r_ent = (ilbd_rule_t *)data;
545dbed73cbSSangeeta Misra 		break;
546dbed73cbSSangeeta Misra 	case ILBD_SCF_SG:
547dbed73cbSSangeeta Misra 		s_ent = (ilbd_sg_t *)data;
548dbed73cbSSangeeta Misra 		break;
549dbed73cbSSangeeta Misra 	case ILBD_SCF_HC:
550dbed73cbSSangeeta Misra 		h_ent = (ilbd_hc_t *)data;
551dbed73cbSSangeeta Misra 		break;
552dbed73cbSSangeeta Misra 	}
553dbed73cbSSangeeta Misra 
554dbed73cbSSangeeta Misra 	v = scf_value_create(h);
555dbed73cbSSangeeta Misra 	if (v == NULL)
556dbed73cbSSangeeta Misra 		return (ILB_STATUS_INTERNAL);
557dbed73cbSSangeeta Misra 
5583ae6a67dSSangeeta Misra 	if ((valstr = malloc(scf_val_len)) == NULL)
5593ae6a67dSSangeeta Misra 			return (ILB_STATUS_ENOMEM);
560dbed73cbSSangeeta Misra 	switch (type) {
561dbed73cbSSangeeta Misra 	case ILBD_RULE_STATUS:
562dbed73cbSSangeeta Misra 		valbool = r_ent->irl_flags & ILB_FLAGS_RULE_ENABLED;
563dbed73cbSSangeeta Misra 		break;
564dbed73cbSSangeeta Misra 	case ILBD_RULE_VIP:
565dbed73cbSSangeeta Misra 		ret = ilbd_scf_ip_to_str(r_ent->irl_ipversion, &r_ent->irl_vip,
566dbed73cbSSangeeta Misra 		    scftype, valstr);
567dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK) {
5683ae6a67dSSangeeta Misra 			free(valstr);
569dbed73cbSSangeeta Misra 			scf_value_destroy(v);
570dbed73cbSSangeeta Misra 			return (ret);
571dbed73cbSSangeeta Misra 		}
572dbed73cbSSangeeta Misra 		break;
573dbed73cbSSangeeta Misra 	case ILBD_RULE_PROTO: {
574dbed73cbSSangeeta Misra 		struct protoent *protoent;
575dbed73cbSSangeeta Misra 
576dbed73cbSSangeeta Misra 		protoent = getprotobynumber(r_ent->irl_proto);
5773ae6a67dSSangeeta Misra 		(void) strlcpy(valstr, protoent->p_name, scf_val_len);
578dbed73cbSSangeeta Misra 		break;
579dbed73cbSSangeeta Misra 	}
580dbed73cbSSangeeta Misra 	case ILBD_RULE_PORT:
5813ae6a67dSSangeeta Misra 		(void) snprintf(valstr, scf_val_len, "%d-%d",
582dbed73cbSSangeeta Misra 		    r_ent->irl_minport, r_ent->irl_maxport);
583dbed73cbSSangeeta Misra 		break;
584dbed73cbSSangeeta Misra 	case ILBD_RULE_ALGO:
585dbed73cbSSangeeta Misra 		ilbd_algo_to_str(r_ent->irl_algo, valstr);
586dbed73cbSSangeeta Misra 		break;
587dbed73cbSSangeeta Misra 	case ILBD_RULE_TOPO:
588dbed73cbSSangeeta Misra 		ilbd_topo_to_str(r_ent->irl_topo, valstr);
589dbed73cbSSangeeta Misra 		break;
590dbed73cbSSangeeta Misra 	case ILBD_RULE_NAT_STR:
591dbed73cbSSangeeta Misra 		ret = ilbd_scf_ip_to_str(r_ent->irl_ipversion,
592dbed73cbSSangeeta Misra 		    &r_ent->irl_nat_src_start, scftype, valstr);
593dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK) {
5943ae6a67dSSangeeta Misra 			free(valstr);
595dbed73cbSSangeeta Misra 			scf_value_destroy(v);
596dbed73cbSSangeeta Misra 			return (ret);
597dbed73cbSSangeeta Misra 		}
598dbed73cbSSangeeta Misra 		break;
599dbed73cbSSangeeta Misra 	case ILBD_RULE_NAT_END:
600dbed73cbSSangeeta Misra 		ret = ilbd_scf_ip_to_str(r_ent->irl_ipversion,
601dbed73cbSSangeeta Misra 		    &r_ent->irl_nat_src_end, scftype, valstr);
602dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK) {
6033ae6a67dSSangeeta Misra 			free(valstr);
604dbed73cbSSangeeta Misra 			scf_value_destroy(v);
605dbed73cbSSangeeta Misra 			return (ret);
606dbed73cbSSangeeta Misra 		}
607dbed73cbSSangeeta Misra 		break;
608dbed73cbSSangeeta Misra 	case ILBD_RULE_STI_MASK:
609dbed73cbSSangeeta Misra 		ret = ilbd_scf_ip_to_str(r_ent->irl_ipversion,
610dbed73cbSSangeeta Misra 		    &r_ent->irl_stickymask, scftype, valstr);
611dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK) {
6123ae6a67dSSangeeta Misra 			free(valstr);
613dbed73cbSSangeeta Misra 			scf_value_destroy(v);
614dbed73cbSSangeeta Misra 			return (ret);
615dbed73cbSSangeeta Misra 		}
616dbed73cbSSangeeta Misra 		break;
617dbed73cbSSangeeta Misra 	case ILBD_RULE_SGNAME:
6183ae6a67dSSangeeta Misra 		(void) strlcpy(valstr, r_ent->irl_sgname, scf_val_len);
619dbed73cbSSangeeta Misra 		break;
620dbed73cbSSangeeta Misra 	case ILBD_RULE_HCNAME:
621dbed73cbSSangeeta Misra 		if (r_ent->irl_hcname[0] != '\0')
622dbed73cbSSangeeta Misra 			(void) strlcpy(valstr, r_ent->irl_hcname,
6233ae6a67dSSangeeta Misra 			    scf_val_len);
624dbed73cbSSangeeta Misra 		else
625dbed73cbSSangeeta Misra 			bzero(valstr, ILBD_MAX_VALUE_LEN);
626dbed73cbSSangeeta Misra 		break;
627dbed73cbSSangeeta Misra 	case ILBD_RULE_HCPORT:
628dbed73cbSSangeeta Misra 		valint = r_ent->irl_hcport;
629dbed73cbSSangeeta Misra 		break;
630dbed73cbSSangeeta Misra 	case ILBD_RULE_HCPFLAG:
631dbed73cbSSangeeta Misra 		valint = r_ent->irl_hcpflag;
632dbed73cbSSangeeta Misra 		break;
633dbed73cbSSangeeta Misra 	case ILBD_RULE_DRAINTIME:
634dbed73cbSSangeeta Misra 		valint = r_ent->irl_conndrain;
635dbed73cbSSangeeta Misra 		break;
636dbed73cbSSangeeta Misra 	case ILBD_RULE_NAT_TO:
637dbed73cbSSangeeta Misra 		valint = r_ent->irl_nat_timeout;
638dbed73cbSSangeeta Misra 		break;
639dbed73cbSSangeeta Misra 	case ILBD_RULE_PERS_TO:
640dbed73cbSSangeeta Misra 		valint = r_ent->irl_sticky_timeout;
641dbed73cbSSangeeta Misra 		break;
642dbed73cbSSangeeta Misra 
643dbed73cbSSangeeta Misra 	case ILBD_SG_SERVER:
644dbed73cbSSangeeta Misra 		if (s_ent->isg_srvcount == 0) {
645dbed73cbSSangeeta Misra 			(void) strlcpy(valstr, "EMPTY_SERVERGROUP",
6463ae6a67dSSangeeta Misra 			    scf_val_len);
647dbed73cbSSangeeta Misra 			break;
648dbed73cbSSangeeta Misra 		}
649dbed73cbSSangeeta Misra 
650dbed73cbSSangeeta Misra 		varray = calloc(sizeof (*varray), s_ent->isg_srvcount);
651dbed73cbSSangeeta Misra 		if (varray == NULL) {
652dbed73cbSSangeeta Misra 			scf_value_destroy(v);
6533ae6a67dSSangeeta Misra 			free(valstr);
654dbed73cbSSangeeta Misra 			return (ILB_STATUS_ENOMEM);
655dbed73cbSSangeeta Misra 		}
656dbed73cbSSangeeta Misra 
657dbed73cbSSangeeta Misra 		for (i = 0; i < s_ent->isg_srvcount; i++) {
658dbed73cbSSangeeta Misra 			if (v == NULL) {
659dbed73cbSSangeeta Misra 				for (i--; i >= 0; i--)
660dbed73cbSSangeeta Misra 					scf_value_destroy(varray[i]);
6613ae6a67dSSangeeta Misra 				free(valstr);
662dbed73cbSSangeeta Misra 				return (ILB_STATUS_ENOMEM);
663dbed73cbSSangeeta Misra 			}
664dbed73cbSSangeeta Misra 
665dbed73cbSSangeeta Misra 			ret = ilbd_get_svr_info(s_ent, i, valstr, NULL);
666dbed73cbSSangeeta Misra 			if (ret != ILB_STATUS_OK) {
667dbed73cbSSangeeta Misra 				scf_value_destroy(v);
668dbed73cbSSangeeta Misra 				for (i--; i >= 0; i--)
669dbed73cbSSangeeta Misra 					scf_value_destroy(varray[i]);
6703ae6a67dSSangeeta Misra 				free(valstr);
671dbed73cbSSangeeta Misra 				free(varray);
672dbed73cbSSangeeta Misra 				return (ret);
673dbed73cbSSangeeta Misra 			}
674dbed73cbSSangeeta Misra 			(void) scf_value_set_astring(v, valstr);
675dbed73cbSSangeeta Misra 			varray[i] = v;
676dbed73cbSSangeeta Misra 			v = scf_value_create(h);
677dbed73cbSSangeeta Misra 		}
678dbed73cbSSangeeta Misra 		/* the last 'v' we created will go unused, so drop it */
679dbed73cbSSangeeta Misra 		scf_value_destroy(v);
680dbed73cbSSangeeta Misra 		*numval = s_ent->isg_srvcount;
681dbed73cbSSangeeta Misra 		*val = varray;
6823ae6a67dSSangeeta Misra 		free(valstr);
683dbed73cbSSangeeta Misra 		return (ret);
684dbed73cbSSangeeta Misra 	case ILBD_HC_TEST:
6853ae6a67dSSangeeta Misra 		(void) strlcpy(valstr, h_ent->ihc_test, scf_val_len);
686dbed73cbSSangeeta Misra 		break;
687dbed73cbSSangeeta Misra 	case ILBD_HC_TIMEOUT:
688dbed73cbSSangeeta Misra 		valint = h_ent->ihc_timeout;
689dbed73cbSSangeeta Misra 		break;
690dbed73cbSSangeeta Misra 	case ILBD_HC_INTERVAL:
691dbed73cbSSangeeta Misra 		valint = h_ent->ihc_interval;
692dbed73cbSSangeeta Misra 		break;
693dbed73cbSSangeeta Misra 	case ILBD_HC_DEF_PING:
694dbed73cbSSangeeta Misra 		valbool = h_ent->ihc_def_ping;
695dbed73cbSSangeeta Misra 		break;
696dbed73cbSSangeeta Misra 	case ILBD_HC_COUNT:
697dbed73cbSSangeeta Misra 		valint = h_ent->ihc_count;
698dbed73cbSSangeeta Misra 		break;
699dbed73cbSSangeeta Misra 	}
700dbed73cbSSangeeta Misra 
701dbed73cbSSangeeta Misra 	switch (*scftype) {
702dbed73cbSSangeeta Misra 	case SCF_TYPE_BOOLEAN:
703dbed73cbSSangeeta Misra 		scf_value_set_boolean(v, valbool);
704dbed73cbSSangeeta Misra 		break;
705dbed73cbSSangeeta Misra 	case SCF_TYPE_ASTRING:
706dbed73cbSSangeeta Misra 		(void) scf_value_set_astring(v, valstr);
707dbed73cbSSangeeta Misra 		break;
708dbed73cbSSangeeta Misra 	case SCF_TYPE_INTEGER:
709dbed73cbSSangeeta Misra 		scf_value_set_integer(v, valint);
710dbed73cbSSangeeta Misra 		break;
711dbed73cbSSangeeta Misra 	case SCF_TYPE_NET_ADDR_V4:
712dbed73cbSSangeeta Misra 		(void) scf_value_set_from_string(v, SCF_TYPE_NET_ADDR_V4,
713dbed73cbSSangeeta Misra 		    valstr);
714dbed73cbSSangeeta Misra 		break;
715dbed73cbSSangeeta Misra 	case SCF_TYPE_NET_ADDR_V6:
716dbed73cbSSangeeta Misra 		(void) scf_value_set_from_string(v, SCF_TYPE_NET_ADDR_V6,
717dbed73cbSSangeeta Misra 		    valstr);
718dbed73cbSSangeeta Misra 		break;
719dbed73cbSSangeeta Misra 	}
7203ae6a67dSSangeeta Misra 	free(valstr);
721dbed73cbSSangeeta Misra 
722dbed73cbSSangeeta Misra 	varray = calloc(1, sizeof (*varray));
723dbed73cbSSangeeta Misra 	if (varray == NULL) {
724dbed73cbSSangeeta Misra 		scf_value_destroy(v);
725dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
726dbed73cbSSangeeta Misra 	}
727dbed73cbSSangeeta Misra 	varray[0] = v;
728dbed73cbSSangeeta Misra 	*val = varray;
729dbed73cbSSangeeta Misra 	*numval = 1;
730dbed73cbSSangeeta Misra 	return (ret);
731dbed73cbSSangeeta Misra }
732dbed73cbSSangeeta Misra 
733dbed73cbSSangeeta Misra /*
734dbed73cbSSangeeta Misra  * create a scf property group
735dbed73cbSSangeeta Misra  */
736dbed73cbSSangeeta Misra ilb_status_t
ilbd_create_pg(ilbd_scf_pg_type_t pg_type,void * data)737dbed73cbSSangeeta Misra ilbd_create_pg(ilbd_scf_pg_type_t pg_type, void *data)
738dbed73cbSSangeeta Misra {
739dbed73cbSSangeeta Misra 	ilb_status_t ret;
740dbed73cbSSangeeta Misra 	char *pgname;
741dbed73cbSSangeeta Misra 	scf_propertygroup_t *pg = NULL;
742dbed73cbSSangeeta Misra 	scf_value_t **val;
743dbed73cbSSangeeta Misra 	scf_handle_t *h;
744dbed73cbSSangeeta Misra 	int scf_name_len = ILBD_MAX_NAME_LEN;
7453ae6a67dSSangeeta Misra 	char  *scfpgbuf; /* property group name or group type */
746dbed73cbSSangeeta Misra 	int i, i_st, i_end;
747dbed73cbSSangeeta Misra 
748dbed73cbSSangeeta Misra 	switch (pg_type) {
749dbed73cbSSangeeta Misra 	case ILBD_SCF_RULE: {
750dbed73cbSSangeeta Misra 		ilbd_rule_t *r_ent = (ilbd_rule_t *)data;
751dbed73cbSSangeeta Misra 
752dbed73cbSSangeeta Misra 		pgname = r_ent->irl_name;
753dbed73cbSSangeeta Misra 		i_st = 0;
754dbed73cbSSangeeta Misra 		i_end = ILBD_RULE_VAR_NUM;
755dbed73cbSSangeeta Misra 		break;
756dbed73cbSSangeeta Misra 	}
757dbed73cbSSangeeta Misra 	case ILBD_SCF_SG: {
758dbed73cbSSangeeta Misra 		ilbd_sg_t *s_ent = (ilbd_sg_t *)data;
759dbed73cbSSangeeta Misra 
760dbed73cbSSangeeta Misra 		pgname = s_ent->isg_name;
761dbed73cbSSangeeta Misra 		i_st = ILBD_RULE_VAR_NUM;
762dbed73cbSSangeeta Misra 		i_end = ILBD_RULE_VAR_NUM + ILBD_SG_VAR_NUM;
763dbed73cbSSangeeta Misra 		break;
764dbed73cbSSangeeta Misra 	}
765dbed73cbSSangeeta Misra 	case ILBD_SCF_HC: {
766dbed73cbSSangeeta Misra 		ilbd_hc_t *h_ent = (ilbd_hc_t *)data;
767dbed73cbSSangeeta Misra 
768dbed73cbSSangeeta Misra 		pgname = h_ent->ihc_name;
769dbed73cbSSangeeta Misra 		i_st = ILBD_RULE_VAR_NUM + ILBD_SG_VAR_NUM;
770dbed73cbSSangeeta Misra 		i_end = ILBD_PROP_VAR_NUM;
771dbed73cbSSangeeta Misra 		break;
772dbed73cbSSangeeta Misra 	}
773dbed73cbSSangeeta Misra 	default:
774dbed73cbSSangeeta Misra 		logdebug("ilbd_create_pg: invalid pg type %d for pg %s",
775dbed73cbSSangeeta Misra 		    pg_type, pgname);
776dbed73cbSSangeeta Misra 		return (ILB_STATUS_EINVAL);
777dbed73cbSSangeeta Misra 	}
7783ae6a67dSSangeeta Misra 	if ((scfpgbuf = malloc(scf_name_len)) == NULL)
7793ae6a67dSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
780dbed73cbSSangeeta Misra 
7813ae6a67dSSangeeta Misra 	ilbd_name_to_scfpgname(pg_type, pgname, scfpgbuf);
782dbed73cbSSangeeta Misra 
7833ae6a67dSSangeeta Misra 	ret = ilbd_scf_retrieve_pg(scfpgbuf, &pg, B_TRUE);
7843ae6a67dSSangeeta Misra 	if (ret != ILB_STATUS_OK) {
7853ae6a67dSSangeeta Misra 		free(scfpgbuf);
786dbed73cbSSangeeta Misra 		return (ret);
7873ae6a67dSSangeeta Misra 	}
788dbed73cbSSangeeta Misra 	h = scf_pg_handle(pg);
789dbed73cbSSangeeta Misra 
790dbed73cbSSangeeta Misra 	/* fill in props */
791dbed73cbSSangeeta Misra 	for (i = i_st; i < i_end; i++) {
792dbed73cbSSangeeta Misra 		int num, j;
793dbed73cbSSangeeta Misra 		scf_type_t scftype = prop_tbl[i].scf_proptype;
794dbed73cbSSangeeta Misra 
795dbed73cbSSangeeta Misra 		ret = ilbd_data_to_scfval(pg_type, prop_tbl[i].val_type, h,
796dbed73cbSSangeeta Misra 		    data, &val, &scftype, &num);
797dbed73cbSSangeeta Misra 		if (ret != ILB_STATUS_OK)
798dbed73cbSSangeeta Misra 			goto done;
799dbed73cbSSangeeta Misra 
800dbed73cbSSangeeta Misra 		for (j = 0; j < num; j++) {
801dbed73cbSSangeeta Misra 			if (pg_type == ILBD_SCF_SG) {
802dbed73cbSSangeeta Misra 				ret = ilbd_get_svr_info(data, j, NULL,
8033ae6a67dSSangeeta Misra 				    scfpgbuf);
804dbed73cbSSangeeta Misra 				if (ret == ILB_STATUS_ENOENT) {
8053ae6a67dSSangeeta Misra 					(void) strlcpy(scfpgbuf,
8063ae6a67dSSangeeta Misra 					    "EMPTY_SERVER", scf_name_len);
807dbed73cbSSangeeta Misra 				}
8083ae6a67dSSangeeta Misra 				ret = ilbd_scf_set_prop(pg, scfpgbuf,
809dbed73cbSSangeeta Misra 				    scftype, val[j]);
810dbed73cbSSangeeta Misra 			} else {
811dbed73cbSSangeeta Misra 				ret = ilbd_scf_set_prop(pg,
812dbed73cbSSangeeta Misra 				    prop_tbl[i].scf_propname, scftype, val[j]);
813dbed73cbSSangeeta Misra 			}
814dbed73cbSSangeeta Misra 			scf_value_destroy(val[j]);
815dbed73cbSSangeeta Misra 		}
816dbed73cbSSangeeta Misra 		free(val);
817dbed73cbSSangeeta Misra 	}
818dbed73cbSSangeeta Misra 
819dbed73cbSSangeeta Misra done:
8203ae6a67dSSangeeta Misra 	free(scfpgbuf);
821dbed73cbSSangeeta Misra 	ilbd_scf_destroy(h, NULL, NULL, pg);
822dbed73cbSSangeeta Misra 	return (ret);
823dbed73cbSSangeeta Misra }