4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
37 #include "libilb_impl.h"
40 #define ILBD_PG_NAME_RULE "rule_"
41 #define ILBD_PG_NAME_SG "sg_"
42 #define ILBD_PG_NAME_HC "hc_"
43 #define ILBD_SVC_FMRI "svc:/network/loadbalancer/ilb"
44 #define ILBD_INST_NAME "default"
75 typedef struct prop_tbl_entry
{
76 ilbd_var_type_t val_type
;
77 const char *scf_propname
;
78 scf_type_t scf_proptype
;
82 * this table contains a map of all SCF properties, including rules,
83 * servergroups and health checks. The place to add new property needs to be
84 * watched carefully. When new properties are added, corresponding *VAR_NUM
85 * needs to be adjusted to reflect the correct index of the table
87 prop_tbl_entry_t prop_tbl
[] = {
88 /* entried for rule */
89 {ILBD_RULE_STATUS
, "status", SCF_TYPE_BOOLEAN
},
90 /* SCF_TYPE_NET_ADDR_V4 or SCF_TYPE_NET_ADDR_V6 */
91 {ILBD_RULE_VIP
, "vip", SCF_TYPE_INVALID
},
92 {ILBD_RULE_PROTO
, "protocol", SCF_TYPE_ASTRING
},
93 {ILBD_RULE_PORT
, "port", SCF_TYPE_ASTRING
},
94 {ILBD_RULE_ALGO
, "ilb-algo", SCF_TYPE_ASTRING
},
95 {ILBD_RULE_TOPO
, "ilb-type", SCF_TYPE_ASTRING
},
96 {ILBD_RULE_NAT_STR
, "ilb-nat-start", SCF_TYPE_INVALID
},
97 {ILBD_RULE_NAT_END
, "ilb-nat-end", SCF_TYPE_INVALID
},
98 {ILBD_RULE_STI_MASK
, "ilb-sti-mask", SCF_TYPE_INVALID
},
99 {ILBD_RULE_SGNAME
, "servergroup", SCF_TYPE_ASTRING
},
100 {ILBD_RULE_HCNAME
, "healthcheck", SCF_TYPE_ASTRING
},
101 {ILBD_RULE_HCPORT
, "hc-port", SCF_TYPE_INTEGER
},
102 {ILBD_RULE_HCPFLAG
, "hcp-flag", SCF_TYPE_INTEGER
},
103 {ILBD_RULE_DRAINTIME
, "drain-time", SCF_TYPE_INTEGER
},
104 {ILBD_RULE_NAT_TO
, "nat-timeout", SCF_TYPE_INTEGER
},
105 {ILBD_RULE_PERS_TO
, "pers-timeout", SCF_TYPE_INTEGER
},
106 /* add new rule related prop here */
108 {ILBD_SG_SERVER
, "server", SCF_TYPE_ASTRING
},
109 /* add new sg related prop here */
111 {ILBD_HC_TEST
, "test", SCF_TYPE_ASTRING
},
112 {ILBD_HC_TIMEOUT
, "timeout", SCF_TYPE_INTEGER
},
113 {ILBD_HC_INTERVAL
, "interval", SCF_TYPE_INTEGER
},
114 {ILBD_HC_DEF_PING
, "ping", SCF_TYPE_BOOLEAN
},
115 /* add new hc related prop here */
116 {ILBD_HC_COUNT
, "count", SCF_TYPE_INTEGER
}
119 #define ILBD_PROP_VAR_NUM (ILBD_HC_COUNT + 1)
120 #define ILBD_RULE_VAR_NUM (ILBD_SG_SERVER)
121 #define ILBD_SG_VAR_NUM (ILBD_HC_TEST - ILBD_SG_SERVER)
122 #define ILBD_HC_VAR_NUM (ILBD_PROP_VAR_NUM - ILBD_HC_TEST)
124 static ilb_status_t
ilbd_scf_set_prop(scf_propertygroup_t
*, const char *,
125 scf_type_t
, scf_value_t
*);
126 static ilb_status_t
ilbd_scf_retrieve_pg(const char *, scf_propertygroup_t
**,
128 static ilb_status_t
ilbd_scf_delete_pg(scf_propertygroup_t
*);
129 static ilb_status_t
ilbd_scf_get_prop_val(scf_propertygroup_t
*, const char *,
132 #define MIN(a, b) ((a) < (b) ? (a) : (b))
135 ilbd_scf_limit(int type
)
137 return (MIN(scf_limit(type
), 120));
141 * Translate libscf error to libilb status
144 ilbd_scf_err_to_ilb_err()
146 switch (scf_error()) {
148 return (ILB_STATUS_OK
);
149 case SCF_ERROR_HANDLE_MISMATCH
:
150 case SCF_ERROR_HANDLE_DESTROYED
:
151 case SCF_ERROR_VERSION_MISMATCH
:
152 case SCF_ERROR_NOT_BOUND
:
153 case SCF_ERROR_CONSTRAINT_VIOLATED
:
154 case SCF_ERROR_NOT_SET
:
155 case SCF_ERROR_TYPE_MISMATCH
:
156 case SCF_ERROR_INVALID_ARGUMENT
:
157 return (ILB_STATUS_EINVAL
);
158 case SCF_ERROR_NO_MEMORY
:
159 case SCF_ERROR_NO_RESOURCES
:
160 return (ILB_STATUS_ENOMEM
);
161 case SCF_ERROR_NOT_FOUND
:
162 case SCF_ERROR_DELETED
:
163 return (ILB_STATUS_ENOENT
);
164 case SCF_ERROR_EXISTS
:
165 return (ILB_STATUS_EEXIST
);
166 case SCF_ERROR_PERMISSION_DENIED
:
167 return (ILB_STATUS_PERMIT
);
168 case SCF_ERROR_CALLBACK_FAILED
:
169 return (ILB_STATUS_CALLBACK
);
170 case SCF_ERROR_IN_USE
:
171 return (ILB_STATUS_INUSE
);
173 return (ILB_STATUS_INTERNAL
);
178 ilbd_name_to_scfpgname(ilbd_scf_pg_type_t pg_type
, const char *pgname
,
183 (void) snprintf(scf_pgname
, ILBD_MAX_NAME_LEN
,
184 ILBD_PG_NAME_RULE
"%s", pgname
);
187 (void) snprintf(scf_pgname
, ILBD_MAX_NAME_LEN
,
188 ILBD_PG_NAME_SG
"%s", pgname
);
191 (void) snprintf(scf_pgname
, ILBD_MAX_NAME_LEN
,
192 ILBD_PG_NAME_HC
"%s", pgname
);
194 /* Should not happen. Log it and put ILB service in maintenance. */
196 logerr("ilbd_name_to_scfpgname: invalid pg type %d for pg %s",
198 (void) smf_maintain_instance(ILB_FMRI
, SMF_IMMEDIATE
);
205 ilbd_scf_destroy(scf_handle_t
*h
, scf_service_t
*s
, scf_instance_t
*inst
,
206 scf_propertygroup_t
*pg
)
211 scf_instance_destroy(inst
);
213 scf_service_destroy(s
);
215 scf_handle_destroy(h
);
220 ilbd_scf_get_inst(scf_handle_t
**h
, scf_service_t
**svc
, scf_instance_t
**inst
)
222 if ((*h
= scf_handle_create(SCF_VERSION
)) == NULL
)
223 return (ILB_STATUS_INTERNAL
);
225 if (scf_handle_bind(*h
) != 0) {
226 ilbd_scf_destroy(*h
, NULL
, NULL
, NULL
);
227 return (ilbd_scf_err_to_ilb_err());
230 if ((*svc
= scf_service_create(*h
)) == NULL
) {
231 ilbd_scf_destroy(*h
, NULL
, NULL
, NULL
);
232 return (ilbd_scf_err_to_ilb_err());
235 if (scf_handle_decode_fmri(*h
, ILBD_SVC_FMRI
, NULL
, *svc
, NULL
, NULL
,
236 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
237 ilbd_scf_destroy(*h
, *svc
, NULL
, NULL
);
238 return (ilbd_scf_err_to_ilb_err());
241 if ((*inst
= scf_instance_create(*h
)) == NULL
) {
242 ilbd_scf_destroy(*h
, *svc
, NULL
, NULL
);
243 return (ilbd_scf_err_to_ilb_err());
246 if (scf_service_get_instance(*svc
, ILBD_INST_NAME
, *inst
) != 0) {
247 ilbd_scf_destroy(*h
, *svc
, *inst
, NULL
);
248 return (ilbd_scf_err_to_ilb_err());
250 return (ILB_STATUS_OK
);
254 * If create is set, create a new prop group, destroy the old one if exists.
255 * If create not set, try to find the prop group with given name.
256 * The created or found entry is returned as *pg.
257 * Caller frees *pg and its handle scf_pg_handle(pg)
260 ilbd_scf_retrieve_pg(const char *pgname
, scf_propertygroup_t
**pg
,
263 scf_instance_t
*inst
;
268 ret
= ilbd_scf_get_inst(&h
, &svc
, &inst
);
269 if (ret
!= ILB_STATUS_OK
)
272 *pg
= scf_pg_create(h
);
274 return (ILB_STATUS_INTERNAL
);
276 if (scf_instance_get_pg(inst
, pgname
, *pg
) != 0) {
277 if (scf_error() != SCF_ERROR_NOT_FOUND
||
278 (scf_error() == SCF_ERROR_NOT_FOUND
&& (!create
))) {
279 ilbd_scf_destroy(h
, svc
, inst
, *pg
);
281 return (ilbd_scf_err_to_ilb_err());
285 * Found pg, don't want to create, return EEXIST. Note that
286 * h cannot be destroyed here since the caller needs to use it.
287 * The caller gets it by calling scf_pg_handle().
290 ilbd_scf_destroy(NULL
, svc
, inst
, NULL
);
291 return (ILB_STATUS_EEXIST
);
293 /* found pg, need to create, destroy the existing one */
295 (void) ilbd_scf_delete_pg(*pg
);
299 if (scf_instance_add_pg(inst
, pgname
,
300 SCF_GROUP_APPLICATION
, 0, *pg
) != 0) {
301 ilbd_scf_destroy(h
, svc
, inst
, *pg
);
303 return (ilbd_scf_err_to_ilb_err());
308 * Note that handle cannot be destroyed here, caller sometimes needs
309 * to use it. It gets the handle by calling scf_pg_handle().
311 ilbd_scf_destroy(NULL
, svc
, inst
, NULL
);
312 return (ILB_STATUS_OK
);
315 struct algo_tbl_entry
{
316 ilb_algo_t algo_type
;
317 const char *algo_str
;
319 {ILB_ALG_ROUNDROBIN
, "ROUNDROBIN"},
320 {ILB_ALG_HASH_IP
, "HASH-IP"},
321 {ILB_ALG_HASH_IP_SPORT
, "HASH-IP-PORT"},
322 {ILB_ALG_HASH_IP_VIP
, "HASH-IP-VIP"}
325 #define ILBD_ALGO_TBL_SIZE (sizeof (algo_tbl) / \
329 ilbd_algo_to_str(ilb_algo_t algo_type
, char *valstr
)
333 for (i
= 0; i
< ILBD_ALGO_TBL_SIZE
; i
++) {
334 if (algo_type
== algo_tbl
[i
].algo_type
) {
335 (void) strlcpy(valstr
, algo_tbl
[i
].algo_str
,
340 logerr("ilbd_algo_to_str: algo not found");
344 ilbd_scf_str_to_algo(ilb_algo_t
*algo_type
, char *valstr
)
348 for (i
= 0; i
< ILBD_ALGO_TBL_SIZE
; i
++) {
349 if (strcmp(valstr
, algo_tbl
[i
].algo_str
) == 0) {
350 *algo_type
= algo_tbl
[i
].algo_type
;
354 logerr("ilbd_scf_str_to_algo: algo not found");
357 struct topo_tbl_entry
{
358 ilb_topo_t topo_type
;
359 const char *topo_str
;
361 {ILB_TOPO_DSR
, "DSR"},
362 {ILB_TOPO_NAT
, "NAT"},
363 {ILB_TOPO_HALF_NAT
, "HALF-NAT"}
366 #define ILBD_TOPO_TBL_SIZE (sizeof (topo_tbl) / \
370 ilbd_topo_to_str(ilb_topo_t topo_type
, char *valstr
)
374 for (i
= 0; i
< ILBD_TOPO_TBL_SIZE
; i
++) {
375 if (topo_type
== topo_tbl
[i
].topo_type
) {
376 (void) strlcpy(valstr
, topo_tbl
[i
].topo_str
,
381 logerr("ilbd_scf_topo_to_str: topo not found");
385 ilbd_scf_str_to_topo(ilb_topo_t
*topo_type
, char *valstr
)
389 for (i
= 0; i
< ILBD_TOPO_TBL_SIZE
; i
++) {
390 if (strcmp(valstr
, topo_tbl
[i
].topo_str
) == 0) {
391 *topo_type
= topo_tbl
[i
].topo_type
;
395 logerr("ilbd_scf_str_to_topo: topo not found");
399 ilbd_get_svr_field(char *valstr
, struct in6_addr
*sgs_addr
,
400 int32_t *min_port
, int32_t *max_port
, int32_t *sgs_flags
)
402 char *ipaddr
, *ipverstr
, *portstr
, *flagstr
;
404 ilb_ip_addr_t temp_ip
;
408 ipaddr
= strtok(valstr
, ";");
409 ipverstr
= strtok(NULL
, ";");
410 portstr
= strtok(NULL
, ";");
411 flagstr
= strtok(NULL
, ";");
413 if (ipaddr
== NULL
|| ipverstr
== NULL
|| portstr
== NULL
||
415 logerr("%s: invalid server fields", __func__
);
416 (void) smf_maintain_instance(ILB_FMRI
, SMF_IMMEDIATE
);
419 ip_ver
= atoi(ipverstr
);
420 addrptr
= (ip_ver
== AF_INET
) ? (void *)&temp_ip
.ia_v4
:
421 (void *)&temp_ip
.ia_v6
;
422 if (inet_pton(ip_ver
, ipaddr
, addrptr
) == 0) {
423 logerr("ilbd_get_svr_field: inet_pton failed");
427 if (ip_ver
== AF_INET
) {
428 IN6_INADDR_TO_V4MAPPED(&(temp_ip
.ia_v4
), sgs_addr
);
430 (void) memcpy(sgs_addr
, &(temp_ip
.ia_v6
),
431 sizeof (struct in6_addr
));
434 *sgs_flags
= atoi(flagstr
);
435 *min_port
= atoi(strtok(portstr
, "-"));
436 *min_port
= ntohs(*min_port
);
437 max_portstr
= strtok(NULL
, "-");
438 if (max_portstr
!= NULL
) {
439 *max_port
= atoi(max_portstr
);
440 *max_port
= ntohs(*max_port
);
445 * Convert the info of a server to its SCF string value representation.
446 * Argument value is assumed to be of size ILBD_MAX_VALUE_LEN.
449 ilbd_srv_scf_val(ilbd_srv_t
*srv
, char *value
)
451 char ipstr
[INET6_ADDRSTRLEN
];
454 if (GET_AF(&srv
->isv_addr
) == AF_INET
) {
455 struct in_addr v4_addr
;
457 IN6_V4MAPPED_TO_INADDR(&srv
->isv_addr
, &v4_addr
);
458 (void) inet_ntop(AF_INET
, &v4_addr
, ipstr
, sizeof (ipstr
));
461 (void) inet_ntop(AF_INET6
, &srv
->isv_addr
, ipstr
,
465 (void) snprintf(value
, ILBD_MAX_VALUE_LEN
, "%s;%d;%d-%d;%d",
466 ipstr
, ipver
, ntohs(srv
->isv_minport
), ntohs(srv
->isv_maxport
),
470 /* get the "ip:port:status" str of the #num server in the servergroup */
472 ilbd_get_svr_info(ilbd_sg_t
*sg
, int num
, char *valstr
, char *svrname
)
475 ilbd_srv_t
*tmp_srv
= NULL
;
477 tmp_srv
= list_head(&sg
->isg_srvlist
);
479 return (ILB_STATUS_ENOENT
);
481 for (i
= 0; i
< num
; i
++)
482 tmp_srv
= list_next(&sg
->isg_srvlist
, tmp_srv
);
484 assert(tmp_srv
!= NULL
);
486 ilbd_srv_scf_val(tmp_srv
, valstr
);
488 if (svrname
!= NULL
) {
489 (void) snprintf(svrname
, ILBD_MAX_NAME_LEN
, "server%d",
493 return (ILB_STATUS_OK
);
496 /* convert a struct in6_addr to valstr */
498 ilbd_scf_ip_to_str(uint16_t ipversion
, struct in6_addr
*addr
,
499 scf_type_t
*scftype
, char *valstr
)
502 ilb_ip_addr_t ipaddr
;
505 vallen
= (ipversion
== AF_INET
) ? INET_ADDRSTRLEN
:
508 *scftype
= (ipversion
== AF_INET
) ? SCF_TYPE_NET_ADDR_V4
:
509 SCF_TYPE_NET_ADDR_V6
;
511 IP_COPY_IMPL_2_CLI(addr
, &ipaddr
);
512 addrptr
= (ipversion
== AF_INET
) ?
513 (void *)&ipaddr
.ia_v4
: (void *)&ipaddr
.ia_v6
;
514 (void) inet_ntop(ipversion
, (void *)addrptr
, valstr
, vallen
);
515 return (ILB_STATUS_OK
);
519 * This function takes a ilbd internal data struct and translate its value to
520 * scf value. The data struct is passed in within "data".
521 * Upon successful return, the scf val will be stored in "val" and the scf type
522 * will be returned in "scftype" if scftype != NULL, the number of values
523 * translated will be in "numval"
524 * If it failed, no data will be written to SCF
527 ilbd_data_to_scfval(ilbd_scf_pg_type_t pg_type
, ilbd_var_type_t type
,
528 scf_handle_t
*h
, void *data
, scf_value_t
***val
, scf_type_t
*scftype
,
531 scf_value_t
*v
, **varray
= NULL
;
532 int ret
= ILB_STATUS_OK
;
534 int scf_val_len
= ILBD_MAX_VALUE_LEN
;
538 ilbd_rule_t
*r_ent
= NULL
;
539 ilbd_sg_t
*s_ent
= NULL
;
540 ilbd_hc_t
*h_ent
= NULL
;
544 r_ent
= (ilbd_rule_t
*)data
;
547 s_ent
= (ilbd_sg_t
*)data
;
550 h_ent
= (ilbd_hc_t
*)data
;
554 v
= scf_value_create(h
);
556 return (ILB_STATUS_INTERNAL
);
558 if ((valstr
= malloc(scf_val_len
)) == NULL
)
559 return (ILB_STATUS_ENOMEM
);
561 case ILBD_RULE_STATUS
:
562 valbool
= r_ent
->irl_flags
& ILB_FLAGS_RULE_ENABLED
;
565 ret
= ilbd_scf_ip_to_str(r_ent
->irl_ipversion
, &r_ent
->irl_vip
,
567 if (ret
!= ILB_STATUS_OK
) {
569 scf_value_destroy(v
);
573 case ILBD_RULE_PROTO
: {
574 struct protoent
*protoent
;
576 protoent
= getprotobynumber(r_ent
->irl_proto
);
577 (void) strlcpy(valstr
, protoent
->p_name
, scf_val_len
);
581 (void) snprintf(valstr
, scf_val_len
, "%d-%d",
582 r_ent
->irl_minport
, r_ent
->irl_maxport
);
585 ilbd_algo_to_str(r_ent
->irl_algo
, valstr
);
588 ilbd_topo_to_str(r_ent
->irl_topo
, valstr
);
590 case ILBD_RULE_NAT_STR
:
591 ret
= ilbd_scf_ip_to_str(r_ent
->irl_ipversion
,
592 &r_ent
->irl_nat_src_start
, scftype
, valstr
);
593 if (ret
!= ILB_STATUS_OK
) {
595 scf_value_destroy(v
);
599 case ILBD_RULE_NAT_END
:
600 ret
= ilbd_scf_ip_to_str(r_ent
->irl_ipversion
,
601 &r_ent
->irl_nat_src_end
, scftype
, valstr
);
602 if (ret
!= ILB_STATUS_OK
) {
604 scf_value_destroy(v
);
608 case ILBD_RULE_STI_MASK
:
609 ret
= ilbd_scf_ip_to_str(r_ent
->irl_ipversion
,
610 &r_ent
->irl_stickymask
, scftype
, valstr
);
611 if (ret
!= ILB_STATUS_OK
) {
613 scf_value_destroy(v
);
617 case ILBD_RULE_SGNAME
:
618 (void) strlcpy(valstr
, r_ent
->irl_sgname
, scf_val_len
);
620 case ILBD_RULE_HCNAME
:
621 if (r_ent
->irl_hcname
[0] != '\0')
622 (void) strlcpy(valstr
, r_ent
->irl_hcname
,
625 bzero(valstr
, ILBD_MAX_VALUE_LEN
);
627 case ILBD_RULE_HCPORT
:
628 valint
= r_ent
->irl_hcport
;
630 case ILBD_RULE_HCPFLAG
:
631 valint
= r_ent
->irl_hcpflag
;
633 case ILBD_RULE_DRAINTIME
:
634 valint
= r_ent
->irl_conndrain
;
636 case ILBD_RULE_NAT_TO
:
637 valint
= r_ent
->irl_nat_timeout
;
639 case ILBD_RULE_PERS_TO
:
640 valint
= r_ent
->irl_sticky_timeout
;
644 if (s_ent
->isg_srvcount
== 0) {
645 (void) strlcpy(valstr
, "EMPTY_SERVERGROUP",
650 varray
= calloc(sizeof (*varray
), s_ent
->isg_srvcount
);
651 if (varray
== NULL
) {
652 scf_value_destroy(v
);
654 return (ILB_STATUS_ENOMEM
);
657 for (i
= 0; i
< s_ent
->isg_srvcount
; i
++) {
659 for (i
--; i
>= 0; i
--)
660 scf_value_destroy(varray
[i
]);
662 return (ILB_STATUS_ENOMEM
);
665 ret
= ilbd_get_svr_info(s_ent
, i
, valstr
, NULL
);
666 if (ret
!= ILB_STATUS_OK
) {
667 scf_value_destroy(v
);
668 for (i
--; i
>= 0; i
--)
669 scf_value_destroy(varray
[i
]);
674 (void) scf_value_set_astring(v
, valstr
);
676 v
= scf_value_create(h
);
678 /* the last 'v' we created will go unused, so drop it */
679 scf_value_destroy(v
);
680 *numval
= s_ent
->isg_srvcount
;
685 (void) strlcpy(valstr
, h_ent
->ihc_test
, scf_val_len
);
687 case ILBD_HC_TIMEOUT
:
688 valint
= h_ent
->ihc_timeout
;
690 case ILBD_HC_INTERVAL
:
691 valint
= h_ent
->ihc_interval
;
693 case ILBD_HC_DEF_PING
:
694 valbool
= h_ent
->ihc_def_ping
;
697 valint
= h_ent
->ihc_count
;
702 case SCF_TYPE_BOOLEAN
:
703 scf_value_set_boolean(v
, valbool
);
705 case SCF_TYPE_ASTRING
:
706 (void) scf_value_set_astring(v
, valstr
);
708 case SCF_TYPE_INTEGER
:
709 scf_value_set_integer(v
, valint
);
711 case SCF_TYPE_NET_ADDR_V4
:
712 (void) scf_value_set_from_string(v
, SCF_TYPE_NET_ADDR_V4
,
715 case SCF_TYPE_NET_ADDR_V6
:
716 (void) scf_value_set_from_string(v
, SCF_TYPE_NET_ADDR_V6
,
722 varray
= calloc(1, sizeof (*varray
));
723 if (varray
== NULL
) {
724 scf_value_destroy(v
);
725 return (ILB_STATUS_ENOMEM
);
734 * create a scf property group
737 ilbd_create_pg(ilbd_scf_pg_type_t pg_type
, void *data
)
741 scf_propertygroup_t
*pg
= NULL
;
744 int scf_name_len
= ILBD_MAX_NAME_LEN
;
745 char *scfpgbuf
; /* property group name or group type */
749 case ILBD_SCF_RULE
: {
750 ilbd_rule_t
*r_ent
= (ilbd_rule_t
*)data
;
752 pgname
= r_ent
->irl_name
;
754 i_end
= ILBD_RULE_VAR_NUM
;
758 ilbd_sg_t
*s_ent
= (ilbd_sg_t
*)data
;
760 pgname
= s_ent
->isg_name
;
761 i_st
= ILBD_RULE_VAR_NUM
;
762 i_end
= ILBD_RULE_VAR_NUM
+ ILBD_SG_VAR_NUM
;
766 ilbd_hc_t
*h_ent
= (ilbd_hc_t
*)data
;
768 pgname
= h_ent
->ihc_name
;
769 i_st
= ILBD_RULE_VAR_NUM
+ ILBD_SG_VAR_NUM
;
770 i_end
= ILBD_PROP_VAR_NUM
;
774 logdebug("ilbd_create_pg: invalid pg type %d for pg %s",
776 return (ILB_STATUS_EINVAL
);
778 if ((scfpgbuf
= malloc(scf_name_len
)) == NULL
)
779 return (ILB_STATUS_ENOMEM
);
781 ilbd_name_to_scfpgname(pg_type
, pgname
, scfpgbuf
);
783 ret
= ilbd_scf_retrieve_pg(scfpgbuf
, &pg
, B_TRUE
);
784 if (ret
!= ILB_STATUS_OK
) {
788 h
= scf_pg_handle(pg
);
791 for (i
= i_st
; i
< i_end
; i
++) {
793 scf_type_t scftype
= prop_tbl
[i
].scf_proptype
;
795 ret
= ilbd_data_to_scfval(pg_type
, prop_tbl
[i
].val_type
, h
,
796 data
, &val
, &scftype
, &num
);
797 if (ret
!= ILB_STATUS_OK
)
800 for (j
= 0; j
< num
; j
++) {
801 if (pg_type
== ILBD_SCF_SG
) {
802 ret
= ilbd_get_svr_info(data
, j
, NULL
,
804 if (ret
== ILB_STATUS_ENOENT
) {
805 (void) strlcpy(scfpgbuf
,
806 "EMPTY_SERVER", scf_name_len
);
808 ret
= ilbd_scf_set_prop(pg
, scfpgbuf
,
811 ret
= ilbd_scf_set_prop(pg
,
812 prop_tbl
[i
].scf_propname
, scftype
, val
[j
]);
814 scf_value_destroy(val
[j
]);
821 ilbd_scf_destroy(h
, NULL
, NULL
, pg
);
826 * destroy a scf property group
829 ilbd_scf_delete_pg(scf_propertygroup_t
*pg
)
831 if (scf_pg_delete(pg
) != 0)
832 return (ilbd_scf_err_to_ilb_err());
833 return (ILB_STATUS_OK
);
836 /* sg can have same name as rule */
838 ilbd_destroy_pg(ilbd_scf_pg_type_t pg_t
, const char *pgname
)
841 scf_propertygroup_t
*pg
;
842 int scf_name_len
= ILBD_MAX_NAME_LEN
;
845 if ((scfname
= malloc(scf_name_len
)) == NULL
)
846 return (ILB_STATUS_ENOMEM
);
847 ilbd_name_to_scfpgname(pg_t
, pgname
, scfname
);
849 ret
= ilbd_scf_retrieve_pg(scfname
, &pg
, B_FALSE
);
851 if (ret
!= ILB_STATUS_EEXIST
)
853 ret
= ilbd_scf_delete_pg(pg
);
854 ilbd_scf_destroy(scf_pg_handle(pg
), NULL
, NULL
, pg
);
859 * Set named property to scf value specified. If property is new,
863 ilbd_scf_set_prop(scf_propertygroup_t
*pg
, const char *propname
,
864 scf_type_t proptype
, scf_value_t
*val
)
866 scf_handle_t
*h
= NULL
;
867 scf_property_t
*prop
= NULL
;
868 scf_value_t
*oldval
= NULL
;
869 scf_transaction_t
*tx
= NULL
;
870 scf_transaction_entry_t
*ent
= NULL
;
871 boolean_t
new = B_FALSE
;
872 ilb_status_t ret
= ILB_STATUS_OK
;
875 h
= scf_pg_handle(pg
);
876 if (h
== NULL
|| propname
== NULL
)
877 return (ILB_STATUS_EINVAL
);
879 ret
= ilbd_scf_get_prop_val(pg
, propname
, &oldval
);
881 scf_value_destroy(oldval
);
882 if (ret
== ILB_STATUS_ENOENT
)
884 else if (ret
!= ILB_STATUS_OK
)
887 if ((prop
= scf_property_create(h
)) == NULL
)
888 return (ilbd_scf_err_to_ilb_err());
889 if ((tx
= scf_transaction_create(h
)) == NULL
||
890 (ent
= scf_entry_create(h
)) == NULL
) {
891 ret
= ilbd_scf_err_to_ilb_err();
892 logdebug("ilbd_scf_set_prop: create scf transaction failed\n");
896 if (scf_transaction_start(tx
, pg
) == -1) {
897 ret
= ilbd_scf_err_to_ilb_err();
898 logdebug("ilbd_scf_set_prop: start scf transaction failed\n");
903 if (scf_transaction_property_new(tx
, ent
, propname
,
905 ret
= ilbd_scf_err_to_ilb_err();
906 logdebug("ilbd_scf_set_prop: create scf prop failed\n");
910 if (scf_transaction_property_change(tx
, ent
, propname
, proptype
)
912 ret
= ilbd_scf_err_to_ilb_err();
913 logdebug("ilbd_scf_set_prop: change scf prop failed\n");
918 if (scf_entry_add_value(ent
, val
) != 0) {
919 logdebug("ilbd_scf_set_prop: add scf entry failed\n");
920 ret
= ilbd_scf_err_to_ilb_err();
924 commit_ret
= scf_transaction_commit(tx
);
925 switch (commit_ret
) {
928 /* update pg here, so subsequent property setting succeeds */
929 (void) scf_pg_update(pg
);
932 /* transaction failed due to not having most recent pg */
933 ret
= ILB_STATUS_INUSE
;
936 ret
= ilbd_scf_err_to_ilb_err();
941 scf_transaction_destroy(tx
);
943 scf_entry_destroy(ent
);
945 scf_property_destroy(prop
);
951 * get a prop's scf val
954 ilbd_scf_get_prop_val(scf_propertygroup_t
*pg
, const char *propname
,
957 scf_handle_t
*h
= NULL
;
958 scf_property_t
*prop
= NULL
;
959 scf_value_t
*value
= NULL
;
960 ilb_status_t ret
= ILB_STATUS_OK
;
962 h
= scf_pg_handle(pg
);
963 if (h
== NULL
|| propname
== NULL
)
964 return (ILB_STATUS_EINVAL
);
966 if ((prop
= scf_property_create(h
)) == NULL
)
967 return (ilbd_scf_err_to_ilb_err());
969 if (scf_pg_get_property(pg
, propname
, prop
) != 0) {
970 ret
= ilbd_scf_err_to_ilb_err();
974 if ((value
= scf_value_create(h
)) == NULL
) {
975 ret
= ilbd_scf_err_to_ilb_err();
979 if (scf_property_get_value(prop
, value
) != 0) {
980 scf_value_destroy(value
);
981 ret
= ilbd_scf_err_to_ilb_err();
988 scf_property_destroy(prop
);
993 typedef struct ilbd_data
996 ilb_sg_info_t
*sg_info
;
997 ilb_hc_info_t
*hc_info
;
998 ilb_rule_info_t
*rule_info
;
1000 ilbd_scf_pg_type_t pg_type
; /* type of data */
1001 #define sg_data data.sg_info
1002 #define hc_data data.hc_info
1003 #define rule_data data.rule_info
1007 ilbd_scf_str_to_ip(int ipversion
, char *ipstr
, struct in6_addr
*addr
)
1009 ilb_ip_addr_t ipaddr
;
1012 addrptr
= (ipversion
== AF_INET
) ?
1013 (void *)&ipaddr
.ia_v4
: (void *)&ipaddr
.ia_v6
;
1014 (void) inet_pton(ipversion
, ipstr
, addrptr
);
1015 if (ipversion
== AF_INET
) {
1016 IN6_INADDR_TO_V4MAPPED(&(ipaddr
.ia_v4
), addr
);
1018 (void) memcpy(addr
, &(ipaddr
.ia_v6
),
1019 sizeof (struct in6_addr
));
1024 * This function takes a scf value and writes it to the correct field of the
1025 * corresponding data struct.
1028 ilbd_scfval_to_data(const char *propname
, ilbd_var_type_t ilb_type
,
1029 scf_value_t
*val
, ilbd_data_t
*ilb_data
)
1032 scf_type_t scf_type
= scf_value_type(val
);
1033 ilbd_scf_pg_type_t pg_type
= ilb_data
->pg_type
;
1035 ilb_rule_info_t
*r_ent
= NULL
;
1036 ilb_sg_info_t
*s_ent
= NULL
;
1037 ilb_hc_info_t
*h_ent
= NULL
;
1038 char ipstr
[INET6_ADDRSTRLEN
];
1046 r_ent
= ilb_data
->rule_data
;
1049 h_ent
= ilb_data
->hc_data
;
1052 s_ent
= ilb_data
->sg_data
;
1056 /* get scf value out */
1057 if ((valstr
= malloc(ILBD_MAX_VALUE_LEN
)) == NULL
)
1058 return (ILB_STATUS_ENOMEM
);
1060 case SCF_TYPE_NET_ADDR_V4
:
1061 if (scf_value_get_as_string_typed(val
,
1062 SCF_TYPE_NET_ADDR_V4
, ipstr
, INET_ADDRSTRLEN
) < 0) {
1064 return (ILB_STATUS_INTERNAL
);
1066 ipversion
= AF_INET
;
1068 case SCF_TYPE_NET_ADDR_V6
:
1069 if (scf_value_get_as_string_typed(val
,
1070 SCF_TYPE_NET_ADDR_V6
, ipstr
,
1071 INET6_ADDRSTRLEN
) < 0) {
1073 return (ILB_STATUS_INTERNAL
);
1075 ipversion
= AF_INET6
;
1077 case SCF_TYPE_BOOLEAN
:
1078 if (scf_value_get_boolean(val
, &valbool
) < 0) {
1080 return (ILB_STATUS_INTERNAL
);
1083 case SCF_TYPE_ASTRING
:
1084 if (scf_value_get_astring(val
, valstr
,
1085 ILBD_MAX_VALUE_LEN
) < 0) {
1087 return (ILB_STATUS_INTERNAL
);
1090 case SCF_TYPE_INTEGER
:
1091 if (scf_value_get_integer(val
, &valint
) < 0) {
1093 return (ILB_STATUS_INTERNAL
);
1098 return (ILB_STATUS_INTERNAL
);
1101 ret
= ILB_STATUS_OK
;
1103 case ILBD_RULE_STATUS
:
1105 r_ent
->rl_flags
|= ILB_FLAGS_RULE_ENABLED
;
1108 r_ent
->rl_ipversion
= ipversion
;
1109 ilbd_scf_str_to_ip(ipversion
, ipstr
, &r_ent
->rl_vip
);
1111 case ILBD_RULE_PROTO
: {
1112 struct protoent
*protoent
;
1114 protoent
= getprotobyname(valstr
);
1115 r_ent
->rl_proto
= protoent
->p_proto
;
1118 case ILBD_RULE_PORT
: {
1119 char *token1
, *token2
;
1121 token1
= strtok(valstr
, "-");
1122 token2
= strtok(NULL
, "-");
1123 r_ent
->rl_minport
= atoi(token1
);
1124 r_ent
->rl_maxport
= atoi(token2
);
1127 case ILBD_RULE_ALGO
:
1128 ilbd_scf_str_to_algo(&(r_ent
->rl_algo
), valstr
);
1130 case ILBD_RULE_TOPO
:
1131 ilbd_scf_str_to_topo(&(r_ent
->rl_topo
), valstr
);
1133 case ILBD_RULE_NAT_STR
:
1134 ilbd_scf_str_to_ip(ipversion
, ipstr
, &r_ent
->rl_nat_src_start
);
1136 case ILBD_RULE_NAT_END
:
1137 ilbd_scf_str_to_ip(ipversion
, ipstr
, &r_ent
->rl_nat_src_end
);
1139 case ILBD_RULE_STI_MASK
:
1140 ilbd_scf_str_to_ip(ipversion
, ipstr
, &r_ent
->rl_stickymask
);
1141 if (ipversion
== AF_INET
) {
1142 if (!IN6_IS_ADDR_V4MAPPED_ANY(&r_ent
->rl_stickymask
))
1143 r_ent
->rl_flags
|= ILB_FLAGS_RULE_STICKY
;
1145 if (!IN6_IS_ADDR_UNSPECIFIED(&r_ent
->rl_stickymask
))
1146 r_ent
->rl_flags
|= ILB_FLAGS_RULE_STICKY
;
1149 case ILBD_RULE_SGNAME
:
1150 (void) strlcpy(r_ent
->rl_sgname
, valstr
,
1151 sizeof (r_ent
->rl_sgname
));
1153 case ILBD_RULE_HCNAME
:
1154 (void) strlcpy(r_ent
->rl_hcname
, valstr
,
1155 sizeof (r_ent
->rl_hcname
));
1157 case ILBD_RULE_HCPORT
:
1158 r_ent
->rl_hcport
= valint
;
1160 case ILBD_RULE_HCPFLAG
:
1161 r_ent
->rl_hcpflag
= valint
;
1163 case ILBD_RULE_DRAINTIME
:
1164 r_ent
->rl_conndrain
= valint
;
1166 case ILBD_RULE_NAT_TO
:
1167 r_ent
->rl_nat_timeout
= valint
;
1169 case ILBD_RULE_PERS_TO
:
1170 r_ent
->rl_sticky_timeout
= valint
;
1173 case ILBD_SG_SERVER
: {
1174 int svr_cnt
= s_ent
->sg_srvcount
;
1176 /* found a new server, increase the svr count of this sg */
1177 s_ent
->sg_srvcount
++;
1180 * valstr contains information of one server in the servergroup
1181 * valstr is in the format of "ip:minport-maxport:enable"
1183 s_ent
= realloc(s_ent
, sizeof (ilb_sg_info_t
) +
1184 s_ent
->sg_srvcount
* sizeof (ilb_sg_srv_t
));
1186 /* sgs_srvID is the sg name, leave it blank */
1188 * sgs_id is the digit in propname, propname is in a format of
1189 * "server" + the digital serverID. We get the serverID by
1190 * reading from the 7th char of propname.
1192 s_ent
->sg_servers
[svr_cnt
].sgs_id
= atoi(&propname
[6]);
1194 ilbd_get_svr_field(valstr
,
1195 &s_ent
->sg_servers
[svr_cnt
].sgs_addr
,
1196 &s_ent
->sg_servers
[svr_cnt
].sgs_minport
,
1197 &s_ent
->sg_servers
[svr_cnt
].sgs_maxport
,
1198 &s_ent
->sg_servers
[svr_cnt
].sgs_flags
);
1199 ilb_data
->sg_data
= s_ent
;
1204 (void) strlcpy(h_ent
->hci_test
, valstr
,
1205 sizeof (h_ent
->hci_test
));
1207 case ILBD_HC_TIMEOUT
:
1208 h_ent
->hci_timeout
= valint
;
1210 case ILBD_HC_INTERVAL
:
1211 h_ent
->hci_interval
= valint
;
1213 case ILBD_HC_DEF_PING
:
1214 h_ent
->hci_def_ping
= valbool
;
1217 h_ent
->hci_count
= valint
;
1219 case ILBD_VAR_INVALID
:
1221 * An empty server group is represented by an invalid
1222 * SCF property. So when loading a server group, this
1223 * case can be hit. But it should happen only for this
1224 * single case. So if it happens in another case, move
1225 * the service into maintenance mode.
1227 if (pg_type
!= ILBD_SCF_SG
|| scf_type
!= SCF_TYPE_ASTRING
) {
1228 logerr("%s: invalid ilb type", __func__
);
1229 (void) smf_maintain_instance(ILB_FMRI
, SMF_IMMEDIATE
);
1231 logdebug("%s: invalid ilb type", __func__
);
1240 static ilbd_var_type_t
1241 ilbd_name_to_valtype(const char *prop_name
)
1245 for (i
= 0; i
< ILBD_PROP_VAR_NUM
; i
++)
1246 if (strncmp(prop_name
, prop_tbl
[i
].scf_propname
,
1247 strlen(prop_tbl
[i
].scf_propname
)) == 0)
1248 return (prop_tbl
[i
].val_type
);
1250 logdebug("ilbd_name_to_valtype: couldn't find prop %s", prop_name
);
1251 return (ILBD_VAR_INVALID
);
1254 /* callback for pg_walk_prop, arg is ilbd_data_t */
1256 ilbd_scf_load_prop(scf_propertygroup_t
*pg
, const char *prop_name
, void *arg
)
1261 ilbd_data_t
*ilb_data
= (ilbd_data_t
*)arg
;
1262 ilbd_var_type_t val_type
= ilbd_name_to_valtype(prop_name
);
1264 h
= scf_pg_handle(pg
);
1266 return (ILB_STATUS_EINVAL
);
1268 ret
= ilbd_scf_get_prop_val(pg
, prop_name
, &val
);
1269 if (ret
== ILB_STATUS_ENOENT
)
1270 return (ILB_STATUS_OK
);
1271 else if (ret
!= ILB_STATUS_OK
)
1275 * Load value to ilb_data.
1277 ret
= ilbd_scfval_to_data(prop_name
, val_type
, val
, ilb_data
);
1281 scf_value_destroy(val
);
1287 * walk properties in one prop group, arg is ilbd_data
1288 * cb is ilbd_scf_load_prop()
1291 ilbd_scf_pg_walk_props(scf_propertygroup_t
*pg
,
1292 ilb_status_t (*cb
)(scf_propertygroup_t
*, const char *, void *),
1296 scf_iter_t
*propiter
;
1297 scf_property_t
*prop
;
1298 int scf_name_len
= ILBD_MAX_NAME_LEN
;
1299 char *prop_name
= NULL
;
1300 ilb_status_t ret
= ILB_STATUS_OK
;
1303 h
= scf_pg_handle(pg
);
1305 return (ILB_STATUS_EINVAL
);
1307 prop
= scf_property_create(h
);
1308 propiter
= scf_iter_create(h
);
1309 if (prop
== NULL
|| propiter
== NULL
)
1312 if (scf_iter_pg_properties(propiter
, pg
) != 0)
1315 if ((prop_name
= malloc(scf_name_len
)) == NULL
) {
1316 ret
= ILB_STATUS_ENOMEM
;
1319 while ((scf_ret
= scf_iter_next_property(propiter
, prop
)) == 1) {
1320 if (scf_property_get_name(prop
, prop_name
, scf_name_len
)
1322 ret
= ilbd_scf_err_to_ilb_err();
1325 ret
= cb(pg
, prop_name
, arg
);
1326 if (ret
!= ILB_STATUS_OK
)
1332 ret
= ilbd_scf_err_to_ilb_err();
1334 scf_property_destroy(prop
);
1335 if (propiter
!= NULL
)
1336 scf_iter_destroy(propiter
);
1341 /* cbs are libd_create_X */
1343 ilbd_scf_instance_walk_pg(scf_instance_t
*inst
,
1344 ilbd_scf_pg_type_t pg_type
,
1345 ilb_status_t (*cb
)(void *, int, struct passwd
*, ucred_t
*),
1346 void *arg1
, void *arg2
)
1352 scf_propertygroup_t
*newpg
;
1353 int port
= *((int *)arg1
);
1354 int scf_name_len
= ILBD_MAX_NAME_LEN
;
1355 char *pg_name
= NULL
;
1358 return (ILB_STATUS_EINVAL
);
1360 h
= scf_instance_handle(inst
);
1362 return (ILB_STATUS_EINVAL
);
1364 if ((newpg
= scf_pg_create(h
)) == NULL
)
1365 return (ilbd_scf_err_to_ilb_err());
1367 if ((pgiter
= scf_iter_create(h
)) == NULL
) {
1368 scf_pg_destroy(newpg
);
1369 return (ilbd_scf_err_to_ilb_err());
1372 if ((scf_ret
= scf_iter_instance_pgs(pgiter
, inst
)) < 0)
1375 if ((pg_name
= malloc(scf_name_len
)) == NULL
) {
1376 ret
= ILB_STATUS_ENOMEM
;
1379 while ((scf_ret
= scf_iter_next_pg(pgiter
, newpg
)) > 0) {
1382 if (scf_pg_get_name(newpg
, pg_name
, scf_name_len
) < 0) {
1383 ret
= ilbd_scf_err_to_ilb_err();
1388 * if pg name indicates it's a ilb configuration, walk its prop
1390 data
.pg_type
= pg_type
;
1391 data
.hc_data
= NULL
;
1392 data
.sg_data
= NULL
;
1393 data
.rule_data
= NULL
;
1397 if (strncmp(ILBD_PG_NAME_RULE
, pg_name
,
1398 strlen(ILBD_PG_NAME_RULE
)) == 0) {
1399 data
.rule_data
= calloc(1,
1400 sizeof (ilb_rule_info_t
));
1401 if (data
.rule_data
== NULL
) {
1402 ret
= ILB_STATUS_ENOMEM
;
1405 ret
= ilbd_scf_pg_walk_props(newpg
,
1406 ilbd_scf_load_prop
, &data
);
1407 if (ret
!= ILB_STATUS_OK
)
1409 assert(data
.rule_data
!= NULL
);
1411 (void) strlcpy(data
.rule_data
->rl_name
,
1412 &pg_name
[strlen(ILBD_PG_NAME_RULE
)],
1413 sizeof (data
.rule_data
->rl_name
));
1415 ret
= cb(data
.rule_data
, port
, arg2
, NULL
);
1416 free(data
.rule_data
);
1417 if (ret
!= ILB_STATUS_OK
)
1422 if (strncmp(ILBD_PG_NAME_SG
, pg_name
,
1423 strlen(ILBD_PG_NAME_SG
)) == 0) {
1424 data
.sg_data
= calloc(1,
1425 sizeof (ilb_sg_info_t
));
1426 if (data
.sg_data
== NULL
) {
1427 ret
= ILB_STATUS_ENOMEM
;
1430 ret
= ilbd_scf_pg_walk_props(newpg
,
1431 ilbd_scf_load_prop
, &data
);
1432 if (ret
!= ILB_STATUS_OK
) {
1436 assert(data
.sg_data
!= NULL
);
1438 (void) strlcpy(data
.sg_data
->sg_name
,
1439 &pg_name
[strlen(ILBD_PG_NAME_SG
)],
1440 sizeof (data
.sg_data
->sg_name
));
1441 ret
= cb(data
.sg_data
, port
, arg2
, NULL
);
1442 if (ret
!= ILB_STATUS_OK
) {
1447 * create a servergroup is two-step operation.
1448 * 1. create an empty servergroup.
1449 * 2. add server(s) to the group.
1451 * since we are here from:
1452 * main_loop()->ilbd_read_config()->
1453 * ilbd_walk_sg_pgs()
1454 * there is no cli to send. So in this
1455 * path auditing will skip the
1456 * adt_set_from_ucred() check
1458 if (data
.sg_data
->sg_srvcount
> 0) {
1459 ret
= ilbd_add_server_to_group(
1460 data
.sg_data
, port
, NULL
, NULL
);
1461 if (ret
!= ILB_STATUS_OK
) {
1470 if (strncmp(ILBD_PG_NAME_HC
, pg_name
,
1471 strlen(ILBD_PG_NAME_HC
)) == 0) {
1472 data
.hc_data
= calloc(1,
1473 sizeof (ilb_hc_info_t
));
1474 if (data
.hc_data
== NULL
) {
1475 ret
= ILB_STATUS_ENOMEM
;
1478 ret
= ilbd_scf_pg_walk_props(newpg
,
1479 ilbd_scf_load_prop
, &data
);
1480 if (ret
!= ILB_STATUS_OK
)
1482 assert(data
.hc_data
!= NULL
);
1484 (void) strlcpy(data
.hc_data
->hci_name
,
1485 &pg_name
[strlen(ILBD_PG_NAME_HC
)],
1486 sizeof (data
.hc_data
->hci_name
));
1487 ret
= cb(data
.hc_data
, port
, arg2
, NULL
);
1489 if (ret
!= ILB_STATUS_OK
)
1499 ret
= ilbd_scf_err_to_ilb_err();
1500 scf_pg_destroy(newpg
);
1501 scf_iter_destroy(pgiter
);
1505 typedef ilb_status_t (*ilbd_scf_walker_fn
)(void *, int, struct passwd
*,
1509 ilbd_walk_rule_pgs(ilb_status_t (*func
)(ilb_rule_info_t
*, int,
1510 const struct passwd
*, ucred_t
*), void *arg1
, void *arg2
)
1512 scf_instance_t
*inst
;
1517 ret
= ilbd_scf_get_inst(&h
, &svc
, &inst
);
1518 if (ret
!= ILB_STATUS_OK
)
1521 /* get rule prop group, transfer it to ilb_lrule_info_t */
1522 ret
= ilbd_scf_instance_walk_pg(inst
, ILBD_SCF_RULE
,
1523 (ilbd_scf_walker_fn
)func
, arg1
, arg2
);
1524 ilbd_scf_destroy(h
, svc
, inst
, NULL
);
1529 ilbd_walk_sg_pgs(ilb_status_t (*func
)(ilb_sg_info_t
*, int,
1530 const struct passwd
*, ucred_t
*), void *arg1
, void *arg2
)
1532 scf_instance_t
*inst
;
1537 ret
= ilbd_scf_get_inst(&h
, &svc
, &inst
);
1538 if (ret
!= ILB_STATUS_OK
)
1541 ret
= ilbd_scf_instance_walk_pg(inst
, ILBD_SCF_SG
,
1542 (ilbd_scf_walker_fn
)func
, arg1
, arg2
);
1543 ilbd_scf_destroy(h
, svc
, inst
, NULL
);
1548 ilbd_walk_hc_pgs(ilb_status_t (*func
)(const ilb_hc_info_t
*, int,
1549 const struct passwd
*, ucred_t
*), void *arg1
, void *arg2
)
1551 scf_instance_t
*inst
;
1556 ret
= ilbd_scf_get_inst(&h
, &svc
, &inst
);
1557 if (ret
!= ILB_STATUS_OK
)
1560 ret
= ilbd_scf_instance_walk_pg(inst
, ILBD_SCF_HC
,
1561 (ilbd_scf_walker_fn
)func
, arg1
, arg2
);
1562 ilbd_scf_destroy(h
, svc
, inst
, NULL
);
1567 ilbd_change_prop(ilbd_scf_pg_type_t pg_type
, const char *pg_name
,
1568 const char *prop_name
, void *new_val
)
1571 scf_propertygroup_t
*scfpg
= NULL
;
1572 char *scf_pgname
= NULL
;
1574 scf_value_t
*scfval
;
1577 if ((scf_pgname
= malloc(ILBD_MAX_NAME_LEN
)) == NULL
)
1578 return (ILB_STATUS_ENOMEM
);
1579 ilbd_name_to_scfpgname(pg_type
, pg_name
, scf_pgname
);
1580 ret
= ilbd_scf_retrieve_pg(scf_pgname
, &scfpg
, B_FALSE
);
1583 if (ret
!= ILB_STATUS_EEXIST
)
1586 assert(scfpg
!= NULL
);
1588 h
= scf_pg_handle(scfpg
);
1590 ret
= ILB_STATUS_EINVAL
;
1594 if ((scfval
= scf_value_create(h
)) == NULL
) {
1595 ret
= ILB_STATUS_ENOMEM
;
1599 if (pg_type
== ILBD_SCF_RULE
) {
1600 scftype
= SCF_TYPE_BOOLEAN
;
1601 scf_value_set_boolean(scfval
, *(boolean_t
*)new_val
);
1602 } else if (pg_type
== ILBD_SCF_SG
) {
1603 scftype
= SCF_TYPE_ASTRING
;
1604 (void) scf_value_set_astring(scfval
, (char *)new_val
);
1606 ret
= ilbd_scf_set_prop(scfpg
, prop_name
, scftype
, scfval
);
1609 if (scf_pg_handle(scfpg
) != NULL
)
1610 scf_handle_destroy(scf_pg_handle(scfpg
));
1612 scf_pg_destroy(scfpg
);
1614 scf_value_destroy(scfval
);
1619 * Update the persistent configuration with a new server, srv, added to a
1623 ilbd_scf_add_srv(ilbd_sg_t
*sg
, ilbd_srv_t
*srv
)
1625 scf_propertygroup_t
*pg
;
1629 int scf_name_len
= ILBD_MAX_NAME_LEN
;
1632 if ((buf
= malloc(scf_name_len
)) == NULL
)
1633 return (ILB_STATUS_ENOMEM
);
1635 ilbd_name_to_scfpgname(ILBD_SCF_SG
, sg
->isg_name
, buf
);
1636 ret
= ilbd_scf_retrieve_pg(buf
, &pg
, B_FALSE
);
1638 * The server group does not exist in persistent storage. This
1639 * cannot happen. Should probably transition the service to
1640 * maintenance since it should be there.
1642 if (ret
!= ILB_STATUS_EEXIST
) {
1643 logerr("ilbd_scf_add_srv: SCF update failed - entering"
1644 " maintenance mode");
1645 (void) smf_maintain_instance(ILB_FMRI
, SMF_IMMEDIATE
);
1647 return (ILB_STATUS_INTERNAL
);
1650 if ((h
= scf_pg_handle(pg
)) == NULL
) {
1651 ilbd_scf_destroy(NULL
, NULL
, NULL
, pg
);
1653 return (ilbd_scf_err_to_ilb_err());
1656 if ((val
= scf_value_create(h
)) == NULL
) {
1657 ilbd_scf_destroy(h
, NULL
, NULL
, pg
);
1659 return (ILB_STATUS_ENOMEM
);
1661 ilbd_srv_scf_val(srv
, buf
);
1662 (void) scf_value_set_astring(val
, buf
);
1664 (void) snprintf(buf
, scf_name_len
, "server%d", srv
->isv_id
);
1665 ret
= ilbd_scf_set_prop(pg
, buf
, SCF_TYPE_ASTRING
, val
);
1667 ilbd_scf_destroy(h
, NULL
, NULL
, pg
);
1668 scf_value_destroy(val
);
1674 * Delete a server, srv, of a server group, sg, from the persistent
1678 ilbd_scf_del_srv(ilbd_sg_t
*sg
, ilbd_srv_t
*srv
)
1681 scf_propertygroup_t
*pg
;
1683 int scf_name_len
= ILBD_MAX_NAME_LEN
;
1685 scf_transaction_t
*tx
= NULL
;
1686 scf_transaction_entry_t
*entry
= NULL
;
1688 if ((buf
= malloc(scf_name_len
)) == NULL
)
1689 return (ILB_STATUS_ENOMEM
);
1690 ilbd_name_to_scfpgname(ILBD_SCF_SG
, sg
->isg_name
, buf
);
1691 ret
= ilbd_scf_retrieve_pg(buf
, &pg
, B_FALSE
);
1693 * The server group does not exist in persistent storage. This
1694 * cannot happen. THe caller of this function puts service in
1697 if (ret
!= ILB_STATUS_EEXIST
) {
1699 return (ILB_STATUS_INTERNAL
);
1701 ret
= ILB_STATUS_OK
;
1703 if ((h
= scf_pg_handle(pg
)) == NULL
) {
1704 logdebug("ilbd_scf_del_srv: scf_pg_handle: %s\n",
1705 scf_strerror(scf_error()));
1706 ilbd_scf_destroy(NULL
, NULL
, NULL
, pg
);
1708 return (ilbd_scf_err_to_ilb_err());
1711 if ((tx
= scf_transaction_create(h
)) == NULL
||
1712 (entry
= scf_entry_create(h
)) == NULL
) {
1713 logdebug("ilbd_scf_del_srv: create scf transaction failed: "
1714 "%s\n", scf_strerror(scf_error()));
1715 ret
= ilbd_scf_err_to_ilb_err();
1719 (void) snprintf(buf
, scf_name_len
, "server%d", srv
->isv_id
);
1721 if (scf_transaction_start(tx
, pg
) == -1) {
1722 logdebug("ilbd_scf_set_prop: start scf transaction failed: "
1723 "%s\n", scf_strerror(scf_error()));
1724 ret
= ilbd_scf_err_to_ilb_err();
1727 if (scf_transaction_property_delete(tx
, entry
, buf
) == -1) {
1728 logdebug("ilbd_scf_set_prop: delete property failed: %s\n",
1729 scf_strerror(scf_error()));
1730 ret
= ilbd_scf_err_to_ilb_err();
1733 if (scf_transaction_commit(tx
) != 1) {
1734 logdebug("ilbd_scf_set_prop: commit transaction failed: %s\n",
1735 scf_strerror(scf_error()));
1736 ret
= ilbd_scf_err_to_ilb_err();
1742 scf_entry_destroy(entry
);
1744 scf_transaction_destroy(tx
);
1745 ilbd_scf_destroy(h
, NULL
, NULL
, pg
);