dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.lib / ilbd / ilbd_scf.c
blobf3acf83e613a00c81b7de775230c0f4f70442818
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <strings.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <sys/list.h>
34 #include <libilb.h>
35 #include <assert.h>
36 #include <libscf.h>
37 #include "libilb_impl.h"
38 #include "ilbd.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"
46 typedef enum {
47 ILBD_RULE_STATUS,
48 ILBD_RULE_VIP,
49 ILBD_RULE_PROTO,
50 ILBD_RULE_PORT,
51 ILBD_RULE_ALGO,
52 ILBD_RULE_TOPO,
53 ILBD_RULE_NAT_STR,
54 ILBD_RULE_NAT_END,
55 ILBD_RULE_STI_MASK,
56 ILBD_RULE_SGNAME,
57 ILBD_RULE_HCNAME,
58 ILBD_RULE_HCPORT,
59 ILBD_RULE_HCPFLAG,
60 ILBD_RULE_DRAINTIME,
61 ILBD_RULE_NAT_TO,
62 ILBD_RULE_PERS_TO,
64 ILBD_SG_SERVER,
66 ILBD_HC_TEST,
67 ILBD_HC_TIMEOUT,
68 ILBD_HC_INTERVAL,
69 ILBD_HC_DEF_PING,
70 ILBD_HC_COUNT,
72 ILBD_VAR_INVALID
73 } ilbd_var_type_t;
75 typedef struct prop_tbl_entry {
76 ilbd_var_type_t val_type;
77 const char *scf_propname;
78 scf_type_t scf_proptype;
79 } prop_tbl_entry_t;
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 */
107 /* entries for sg */
108 {ILBD_SG_SERVER, "server", SCF_TYPE_ASTRING},
109 /* add new sg related prop here */
110 /* entries for hc */
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 **,
127 boolean_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 *,
130 scf_value_t **);
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
143 ilb_status_t
144 ilbd_scf_err_to_ilb_err()
146 switch (scf_error()) {
147 case SCF_ERROR_NONE:
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);
172 default:
173 return (ILB_STATUS_INTERNAL);
177 static void
178 ilbd_name_to_scfpgname(ilbd_scf_pg_type_t pg_type, const char *pgname,
179 char *scf_pgname)
181 switch (pg_type) {
182 case ILBD_SCF_RULE:
183 (void) snprintf(scf_pgname, ILBD_MAX_NAME_LEN,
184 ILBD_PG_NAME_RULE "%s", pgname);
185 return;
186 case ILBD_SCF_SG:
187 (void) snprintf(scf_pgname, ILBD_MAX_NAME_LEN,
188 ILBD_PG_NAME_SG "%s", pgname);
189 return;
190 case ILBD_SCF_HC:
191 (void) snprintf(scf_pgname, ILBD_MAX_NAME_LEN,
192 ILBD_PG_NAME_HC "%s", pgname);
193 return;
194 /* Should not happen. Log it and put ILB service in maintenance. */
195 default:
196 logerr("ilbd_name_to_scfpgname: invalid pg type %d for pg %s",
197 pg_type, pgname);
198 (void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE);
199 exit(EXIT_FAILURE);
200 return;
204 static void
205 ilbd_scf_destroy(scf_handle_t *h, scf_service_t *s, scf_instance_t *inst,
206 scf_propertygroup_t *pg)
208 if (pg != NULL)
209 scf_pg_destroy(pg);
210 if (inst != NULL)
211 scf_instance_destroy(inst);
212 if (s != NULL)
213 scf_service_destroy(s);
214 if (h != NULL)
215 scf_handle_destroy(h);
219 static ilb_status_t
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)
259 static ilb_status_t
260 ilbd_scf_retrieve_pg(const char *pgname, scf_propertygroup_t **pg,
261 boolean_t create)
263 scf_instance_t *inst;
264 scf_handle_t *h;
265 scf_service_t *svc;
266 ilb_status_t ret;
268 ret = ilbd_scf_get_inst(&h, &svc, &inst);
269 if (ret != ILB_STATUS_OK)
270 return (ret);
272 *pg = scf_pg_create(h);
273 if (*pg == NULL)
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);
280 *pg = NULL;
281 return (ilbd_scf_err_to_ilb_err());
283 } else {
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().
289 if (!create) {
290 ilbd_scf_destroy(NULL, svc, inst, NULL);
291 return (ILB_STATUS_EEXIST);
293 /* found pg, need to create, destroy the existing one */
294 else
295 (void) ilbd_scf_delete_pg(*pg);
298 if (create) {
299 if (scf_instance_add_pg(inst, pgname,
300 SCF_GROUP_APPLICATION, 0, *pg) != 0) {
301 ilbd_scf_destroy(h, svc, inst, *pg);
302 *pg = NULL;
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;
318 } algo_tbl[] = {
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) / \
326 sizeof (*algo_tbl))
328 void
329 ilbd_algo_to_str(ilb_algo_t algo_type, char *valstr)
331 int i;
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,
336 ILBD_MAX_VALUE_LEN);
337 return;
340 logerr("ilbd_algo_to_str: algo not found");
343 static void
344 ilbd_scf_str_to_algo(ilb_algo_t *algo_type, char *valstr)
346 int i;
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;
351 return;
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;
360 } topo_tbl[] = {
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) / \
367 sizeof (*topo_tbl))
369 void
370 ilbd_topo_to_str(ilb_topo_t topo_type, char *valstr)
372 int i;
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,
377 ILBD_MAX_VALUE_LEN);
378 return;
381 logerr("ilbd_scf_topo_to_str: topo not found");
384 static void
385 ilbd_scf_str_to_topo(ilb_topo_t *topo_type, char *valstr)
387 int i;
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;
392 return;
395 logerr("ilbd_scf_str_to_topo: topo not found");
398 static void
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;
403 int ip_ver;
404 ilb_ip_addr_t temp_ip;
405 void *addrptr;
406 char *max_portstr;
408 ipaddr = strtok(valstr, ";");
409 ipverstr = strtok(NULL, ";");
410 portstr = strtok(NULL, ";");
411 flagstr = strtok(NULL, ";");
413 if (ipaddr == NULL || ipverstr == NULL || portstr == NULL ||
414 flagstr == NULL) {
415 logerr("%s: invalid server fields", __func__);
416 (void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE);
417 exit(EXIT_FAILURE);
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");
424 return;
427 if (ip_ver == AF_INET) {
428 IN6_INADDR_TO_V4MAPPED(&(temp_ip.ia_v4), sgs_addr);
429 } else {
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.
448 static void
449 ilbd_srv_scf_val(ilbd_srv_t *srv, char *value)
451 char ipstr[INET6_ADDRSTRLEN];
452 int ipver;
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));
459 ipver = AF_INET;
460 } else {
461 (void) inet_ntop(AF_INET6, &srv->isv_addr, ipstr,
462 sizeof (ipstr));
463 ipver = AF_INET6;
465 (void) snprintf(value, ILBD_MAX_VALUE_LEN, "%s;%d;%d-%d;%d",
466 ipstr, ipver, ntohs(srv->isv_minport), ntohs(srv->isv_maxport),
467 srv->isv_flags);
470 /* get the "ip:port:status" str of the #num server in the servergroup */
471 ilb_status_t
472 ilbd_get_svr_info(ilbd_sg_t *sg, int num, char *valstr, char *svrname)
474 int i;
475 ilbd_srv_t *tmp_srv = NULL;
477 tmp_srv = list_head(&sg->isg_srvlist);
478 if (tmp_srv == NULL)
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);
485 if (valstr != NULL)
486 ilbd_srv_scf_val(tmp_srv, valstr);
488 if (svrname != NULL) {
489 (void) snprintf(svrname, ILBD_MAX_NAME_LEN, "server%d",
490 tmp_srv->isv_id);
493 return (ILB_STATUS_OK);
496 /* convert a struct in6_addr to valstr */
497 ilb_status_t
498 ilbd_scf_ip_to_str(uint16_t ipversion, struct in6_addr *addr,
499 scf_type_t *scftype, char *valstr)
501 size_t vallen;
502 ilb_ip_addr_t ipaddr;
503 void *addrptr;
505 vallen = (ipversion == AF_INET) ? INET_ADDRSTRLEN :
506 INET6_ADDRSTRLEN;
507 if (scftype != NULL)
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
526 static ilb_status_t
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,
529 int *numval)
531 scf_value_t *v, **varray = NULL;
532 int ret = ILB_STATUS_OK;
533 int i;
534 int scf_val_len = ILBD_MAX_VALUE_LEN;
535 char *valstr = NULL;
536 int valint;
537 uint8_t valbool = 0;
538 ilbd_rule_t *r_ent = NULL;
539 ilbd_sg_t *s_ent = NULL;
540 ilbd_hc_t *h_ent = NULL;
542 switch (pg_type) {
543 case ILBD_SCF_RULE:
544 r_ent = (ilbd_rule_t *)data;
545 break;
546 case ILBD_SCF_SG:
547 s_ent = (ilbd_sg_t *)data;
548 break;
549 case ILBD_SCF_HC:
550 h_ent = (ilbd_hc_t *)data;
551 break;
554 v = scf_value_create(h);
555 if (v == NULL)
556 return (ILB_STATUS_INTERNAL);
558 if ((valstr = malloc(scf_val_len)) == NULL)
559 return (ILB_STATUS_ENOMEM);
560 switch (type) {
561 case ILBD_RULE_STATUS:
562 valbool = r_ent->irl_flags & ILB_FLAGS_RULE_ENABLED;
563 break;
564 case ILBD_RULE_VIP:
565 ret = ilbd_scf_ip_to_str(r_ent->irl_ipversion, &r_ent->irl_vip,
566 scftype, valstr);
567 if (ret != ILB_STATUS_OK) {
568 free(valstr);
569 scf_value_destroy(v);
570 return (ret);
572 break;
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);
578 break;
580 case ILBD_RULE_PORT:
581 (void) snprintf(valstr, scf_val_len, "%d-%d",
582 r_ent->irl_minport, r_ent->irl_maxport);
583 break;
584 case ILBD_RULE_ALGO:
585 ilbd_algo_to_str(r_ent->irl_algo, valstr);
586 break;
587 case ILBD_RULE_TOPO:
588 ilbd_topo_to_str(r_ent->irl_topo, valstr);
589 break;
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) {
594 free(valstr);
595 scf_value_destroy(v);
596 return (ret);
598 break;
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) {
603 free(valstr);
604 scf_value_destroy(v);
605 return (ret);
607 break;
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) {
612 free(valstr);
613 scf_value_destroy(v);
614 return (ret);
616 break;
617 case ILBD_RULE_SGNAME:
618 (void) strlcpy(valstr, r_ent->irl_sgname, scf_val_len);
619 break;
620 case ILBD_RULE_HCNAME:
621 if (r_ent->irl_hcname[0] != '\0')
622 (void) strlcpy(valstr, r_ent->irl_hcname,
623 scf_val_len);
624 else
625 bzero(valstr, ILBD_MAX_VALUE_LEN);
626 break;
627 case ILBD_RULE_HCPORT:
628 valint = r_ent->irl_hcport;
629 break;
630 case ILBD_RULE_HCPFLAG:
631 valint = r_ent->irl_hcpflag;
632 break;
633 case ILBD_RULE_DRAINTIME:
634 valint = r_ent->irl_conndrain;
635 break;
636 case ILBD_RULE_NAT_TO:
637 valint = r_ent->irl_nat_timeout;
638 break;
639 case ILBD_RULE_PERS_TO:
640 valint = r_ent->irl_sticky_timeout;
641 break;
643 case ILBD_SG_SERVER:
644 if (s_ent->isg_srvcount == 0) {
645 (void) strlcpy(valstr, "EMPTY_SERVERGROUP",
646 scf_val_len);
647 break;
650 varray = calloc(sizeof (*varray), s_ent->isg_srvcount);
651 if (varray == NULL) {
652 scf_value_destroy(v);
653 free(valstr);
654 return (ILB_STATUS_ENOMEM);
657 for (i = 0; i < s_ent->isg_srvcount; i++) {
658 if (v == NULL) {
659 for (i--; i >= 0; i--)
660 scf_value_destroy(varray[i]);
661 free(valstr);
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]);
670 free(valstr);
671 free(varray);
672 return (ret);
674 (void) scf_value_set_astring(v, valstr);
675 varray[i] = v;
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;
681 *val = varray;
682 free(valstr);
683 return (ret);
684 case ILBD_HC_TEST:
685 (void) strlcpy(valstr, h_ent->ihc_test, scf_val_len);
686 break;
687 case ILBD_HC_TIMEOUT:
688 valint = h_ent->ihc_timeout;
689 break;
690 case ILBD_HC_INTERVAL:
691 valint = h_ent->ihc_interval;
692 break;
693 case ILBD_HC_DEF_PING:
694 valbool = h_ent->ihc_def_ping;
695 break;
696 case ILBD_HC_COUNT:
697 valint = h_ent->ihc_count;
698 break;
701 switch (*scftype) {
702 case SCF_TYPE_BOOLEAN:
703 scf_value_set_boolean(v, valbool);
704 break;
705 case SCF_TYPE_ASTRING:
706 (void) scf_value_set_astring(v, valstr);
707 break;
708 case SCF_TYPE_INTEGER:
709 scf_value_set_integer(v, valint);
710 break;
711 case SCF_TYPE_NET_ADDR_V4:
712 (void) scf_value_set_from_string(v, SCF_TYPE_NET_ADDR_V4,
713 valstr);
714 break;
715 case SCF_TYPE_NET_ADDR_V6:
716 (void) scf_value_set_from_string(v, SCF_TYPE_NET_ADDR_V6,
717 valstr);
718 break;
720 free(valstr);
722 varray = calloc(1, sizeof (*varray));
723 if (varray == NULL) {
724 scf_value_destroy(v);
725 return (ILB_STATUS_ENOMEM);
727 varray[0] = v;
728 *val = varray;
729 *numval = 1;
730 return (ret);
734 * create a scf property group
736 ilb_status_t
737 ilbd_create_pg(ilbd_scf_pg_type_t pg_type, void *data)
739 ilb_status_t ret;
740 char *pgname;
741 scf_propertygroup_t *pg = NULL;
742 scf_value_t **val;
743 scf_handle_t *h;
744 int scf_name_len = ILBD_MAX_NAME_LEN;
745 char *scfpgbuf; /* property group name or group type */
746 int i, i_st, i_end;
748 switch (pg_type) {
749 case ILBD_SCF_RULE: {
750 ilbd_rule_t *r_ent = (ilbd_rule_t *)data;
752 pgname = r_ent->irl_name;
753 i_st = 0;
754 i_end = ILBD_RULE_VAR_NUM;
755 break;
757 case ILBD_SCF_SG: {
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;
763 break;
765 case ILBD_SCF_HC: {
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;
771 break;
773 default:
774 logdebug("ilbd_create_pg: invalid pg type %d for pg %s",
775 pg_type, pgname);
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) {
785 free(scfpgbuf);
786 return (ret);
788 h = scf_pg_handle(pg);
790 /* fill in props */
791 for (i = i_st; i < i_end; i++) {
792 int num, j;
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)
798 goto done;
800 for (j = 0; j < num; j++) {
801 if (pg_type == ILBD_SCF_SG) {
802 ret = ilbd_get_svr_info(data, j, NULL,
803 scfpgbuf);
804 if (ret == ILB_STATUS_ENOENT) {
805 (void) strlcpy(scfpgbuf,
806 "EMPTY_SERVER", scf_name_len);
808 ret = ilbd_scf_set_prop(pg, scfpgbuf,
809 scftype, val[j]);
810 } else {
811 ret = ilbd_scf_set_prop(pg,
812 prop_tbl[i].scf_propname, scftype, val[j]);
814 scf_value_destroy(val[j]);
816 free(val);
819 done:
820 free(scfpgbuf);
821 ilbd_scf_destroy(h, NULL, NULL, pg);
822 return (ret);
826 * destroy a scf property group
828 static ilb_status_t
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 */
837 ilb_status_t
838 ilbd_destroy_pg(ilbd_scf_pg_type_t pg_t, const char *pgname)
840 ilb_status_t ret;
841 scf_propertygroup_t *pg;
842 int scf_name_len = ILBD_MAX_NAME_LEN;
843 char *scfname;
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);
850 free(scfname);
851 if (ret != ILB_STATUS_EEXIST)
852 return (ret);
853 ret = ilbd_scf_delete_pg(pg);
854 ilbd_scf_destroy(scf_pg_handle(pg), NULL, NULL, pg);
855 return (ret);
859 * Set named property to scf value specified. If property is new,
860 * create it.
862 static ilb_status_t
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;
873 int commit_ret;
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);
880 if (oldval != NULL)
881 scf_value_destroy(oldval);
882 if (ret == ILB_STATUS_ENOENT)
883 new = B_TRUE;
884 else if (ret != ILB_STATUS_OK)
885 return (ret);
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");
893 goto out;
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");
899 goto out;
902 if (new) {
903 if (scf_transaction_property_new(tx, ent, propname,
904 proptype) == -1) {
905 ret = ilbd_scf_err_to_ilb_err();
906 logdebug("ilbd_scf_set_prop: create scf prop failed\n");
907 goto out;
909 } else {
910 if (scf_transaction_property_change(tx, ent, propname, proptype)
911 == -1) {
912 ret = ilbd_scf_err_to_ilb_err();
913 logdebug("ilbd_scf_set_prop: change scf prop failed\n");
914 goto out;
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();
921 goto out;
924 commit_ret = scf_transaction_commit(tx);
925 switch (commit_ret) {
926 case 1:
927 ret = ILB_STATUS_OK;
928 /* update pg here, so subsequent property setting succeeds */
929 (void) scf_pg_update(pg);
930 break;
931 case 0:
932 /* transaction failed due to not having most recent pg */
933 ret = ILB_STATUS_INUSE;
934 break;
935 default:
936 ret = ilbd_scf_err_to_ilb_err();
937 break;
939 out:
940 if (tx != NULL)
941 scf_transaction_destroy(tx);
942 if (ent != NULL)
943 scf_entry_destroy(ent);
944 if (prop != NULL)
945 scf_property_destroy(prop);
947 return (ret);
951 * get a prop's scf val
953 static ilb_status_t
954 ilbd_scf_get_prop_val(scf_propertygroup_t *pg, const char *propname,
955 scf_value_t **val)
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();
971 goto out;
974 if ((value = scf_value_create(h)) == NULL) {
975 ret = ilbd_scf_err_to_ilb_err();
976 goto out;
979 if (scf_property_get_value(prop, value) != 0) {
980 scf_value_destroy(value);
981 ret = ilbd_scf_err_to_ilb_err();
982 goto out;
985 *val = value;
986 out:
987 if (prop != NULL)
988 scf_property_destroy(prop);
990 return (ret);
993 typedef struct ilbd_data
995 union {
996 ilb_sg_info_t *sg_info;
997 ilb_hc_info_t *hc_info;
998 ilb_rule_info_t *rule_info;
999 } data;
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
1004 } ilbd_data_t;
1006 void
1007 ilbd_scf_str_to_ip(int ipversion, char *ipstr, struct in6_addr *addr)
1009 ilb_ip_addr_t ipaddr;
1010 void *addrptr;
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);
1017 } else {
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.
1027 static ilb_status_t
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;
1034 int ret = 0;
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];
1039 char *valstr;
1040 int64_t valint;
1041 uint8_t valbool;
1042 int ipversion;
1044 switch (pg_type) {
1045 case ILBD_SCF_RULE:
1046 r_ent = ilb_data->rule_data;
1047 break;
1048 case ILBD_SCF_HC:
1049 h_ent = ilb_data->hc_data;
1050 break;
1051 case ILBD_SCF_SG:
1052 s_ent = ilb_data->sg_data;
1053 break;
1056 /* get scf value out */
1057 if ((valstr = malloc(ILBD_MAX_VALUE_LEN)) == NULL)
1058 return (ILB_STATUS_ENOMEM);
1059 switch (scf_type) {
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) {
1063 free(valstr);
1064 return (ILB_STATUS_INTERNAL);
1066 ipversion = AF_INET;
1067 break;
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) {
1072 free(valstr);
1073 return (ILB_STATUS_INTERNAL);
1075 ipversion = AF_INET6;
1076 break;
1077 case SCF_TYPE_BOOLEAN:
1078 if (scf_value_get_boolean(val, &valbool) < 0) {
1079 free(valstr);
1080 return (ILB_STATUS_INTERNAL);
1082 break;
1083 case SCF_TYPE_ASTRING:
1084 if (scf_value_get_astring(val, valstr,
1085 ILBD_MAX_VALUE_LEN) < 0) {
1086 free(valstr);
1087 return (ILB_STATUS_INTERNAL);
1089 break;
1090 case SCF_TYPE_INTEGER:
1091 if (scf_value_get_integer(val, &valint) < 0) {
1092 free(valstr);
1093 return (ILB_STATUS_INTERNAL);
1095 break;
1096 default:
1097 free(valstr);
1098 return (ILB_STATUS_INTERNAL);
1101 ret = ILB_STATUS_OK;
1102 switch (ilb_type) {
1103 case ILBD_RULE_STATUS:
1104 if (valbool)
1105 r_ent->rl_flags |= ILB_FLAGS_RULE_ENABLED;
1106 break;
1107 case ILBD_RULE_VIP:
1108 r_ent->rl_ipversion = ipversion;
1109 ilbd_scf_str_to_ip(ipversion, ipstr, &r_ent->rl_vip);
1110 break;
1111 case ILBD_RULE_PROTO: {
1112 struct protoent *protoent;
1114 protoent = getprotobyname(valstr);
1115 r_ent->rl_proto = protoent->p_proto;
1116 break;
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);
1125 break;
1127 case ILBD_RULE_ALGO:
1128 ilbd_scf_str_to_algo(&(r_ent->rl_algo), valstr);
1129 break;
1130 case ILBD_RULE_TOPO:
1131 ilbd_scf_str_to_topo(&(r_ent->rl_topo), valstr);
1132 break;
1133 case ILBD_RULE_NAT_STR:
1134 ilbd_scf_str_to_ip(ipversion, ipstr, &r_ent->rl_nat_src_start);
1135 break;
1136 case ILBD_RULE_NAT_END:
1137 ilbd_scf_str_to_ip(ipversion, ipstr, &r_ent->rl_nat_src_end);
1138 break;
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;
1144 } else {
1145 if (!IN6_IS_ADDR_UNSPECIFIED(&r_ent->rl_stickymask))
1146 r_ent->rl_flags |= ILB_FLAGS_RULE_STICKY;
1148 break;
1149 case ILBD_RULE_SGNAME:
1150 (void) strlcpy(r_ent->rl_sgname, valstr,
1151 sizeof (r_ent->rl_sgname));
1152 break;
1153 case ILBD_RULE_HCNAME:
1154 (void) strlcpy(r_ent->rl_hcname, valstr,
1155 sizeof (r_ent->rl_hcname));
1156 break;
1157 case ILBD_RULE_HCPORT:
1158 r_ent->rl_hcport = valint;
1159 break;
1160 case ILBD_RULE_HCPFLAG:
1161 r_ent->rl_hcpflag = valint;
1162 break;
1163 case ILBD_RULE_DRAINTIME:
1164 r_ent->rl_conndrain = valint;
1165 break;
1166 case ILBD_RULE_NAT_TO:
1167 r_ent->rl_nat_timeout = valint;
1168 break;
1169 case ILBD_RULE_PERS_TO:
1170 r_ent->rl_sticky_timeout = valint;
1171 break;
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;
1201 break;
1203 case ILBD_HC_TEST:
1204 (void) strlcpy(h_ent->hci_test, valstr,
1205 sizeof (h_ent->hci_test));
1206 break;
1207 case ILBD_HC_TIMEOUT:
1208 h_ent->hci_timeout = valint;
1209 break;
1210 case ILBD_HC_INTERVAL:
1211 h_ent->hci_interval = valint;
1212 break;
1213 case ILBD_HC_DEF_PING:
1214 h_ent->hci_def_ping = valbool;
1215 break;
1216 case ILBD_HC_COUNT:
1217 h_ent->hci_count = valint;
1218 break;
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);
1230 } else {
1231 logdebug("%s: invalid ilb type", __func__);
1233 break;
1236 free(valstr);
1237 return (ret);
1240 static ilbd_var_type_t
1241 ilbd_name_to_valtype(const char *prop_name)
1243 int i;
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 */
1255 static ilb_status_t
1256 ilbd_scf_load_prop(scf_propertygroup_t *pg, const char *prop_name, void *arg)
1258 scf_handle_t *h;
1259 scf_value_t *val;
1260 ilb_status_t ret;
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);
1265 if (h == NULL)
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)
1272 return (ret);
1275 * Load value to ilb_data.
1277 ret = ilbd_scfval_to_data(prop_name, val_type, val, ilb_data);
1279 out:
1280 if (val != NULL)
1281 scf_value_destroy(val);
1283 return (ret);
1287 * walk properties in one prop group, arg is ilbd_data
1288 * cb is ilbd_scf_load_prop()
1290 static ilb_status_t
1291 ilbd_scf_pg_walk_props(scf_propertygroup_t *pg,
1292 ilb_status_t (*cb)(scf_propertygroup_t *, const char *, void *),
1293 void *arg)
1295 scf_handle_t *h;
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;
1301 int scf_ret = -1;
1303 h = scf_pg_handle(pg);
1304 if (h == NULL)
1305 return (ILB_STATUS_EINVAL);
1307 prop = scf_property_create(h);
1308 propiter = scf_iter_create(h);
1309 if (prop == NULL || propiter == NULL)
1310 goto out;
1312 if (scf_iter_pg_properties(propiter, pg) != 0)
1313 goto out;
1315 if ((prop_name = malloc(scf_name_len)) == NULL) {
1316 ret = ILB_STATUS_ENOMEM;
1317 goto out;
1319 while ((scf_ret = scf_iter_next_property(propiter, prop)) == 1) {
1320 if (scf_property_get_name(prop, prop_name, scf_name_len)
1321 < 0) {
1322 ret = ilbd_scf_err_to_ilb_err();
1323 goto out;
1325 ret = cb(pg, prop_name, arg);
1326 if (ret != ILB_STATUS_OK)
1327 break;
1329 out:
1330 free(prop_name);
1331 if (scf_ret == -1)
1332 ret = ilbd_scf_err_to_ilb_err();
1333 if (prop != NULL)
1334 scf_property_destroy(prop);
1335 if (propiter != NULL)
1336 scf_iter_destroy(propiter);
1338 return (ret);
1341 /* cbs are libd_create_X */
1342 static ilb_status_t
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)
1348 int scf_ret;
1349 ilb_status_t ret;
1350 scf_handle_t *h;
1351 scf_iter_t *pgiter;
1352 scf_propertygroup_t *newpg;
1353 int port = *((int *)arg1);
1354 int scf_name_len = ILBD_MAX_NAME_LEN;
1355 char *pg_name = NULL;
1357 if (inst == NULL)
1358 return (ILB_STATUS_EINVAL);
1360 h = scf_instance_handle(inst);
1361 if (h == NULL)
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)
1373 goto out;
1375 if ((pg_name = malloc(scf_name_len)) == NULL) {
1376 ret = ILB_STATUS_ENOMEM;
1377 goto out;
1379 while ((scf_ret = scf_iter_next_pg(pgiter, newpg)) > 0) {
1380 ilbd_data_t data;
1382 if (scf_pg_get_name(newpg, pg_name, scf_name_len) < 0) {
1383 ret = ilbd_scf_err_to_ilb_err();
1384 goto out;
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;
1395 switch (pg_type) {
1396 case ILBD_SCF_RULE:
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;
1403 goto out;
1405 ret = ilbd_scf_pg_walk_props(newpg,
1406 ilbd_scf_load_prop, &data);
1407 if (ret != ILB_STATUS_OK)
1408 goto out;
1409 assert(data.rule_data != NULL);
1410 /* set rule name */
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)
1418 goto out;
1420 break;
1421 case ILBD_SCF_SG:
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;
1428 goto out;
1430 ret = ilbd_scf_pg_walk_props(newpg,
1431 ilbd_scf_load_prop, &data);
1432 if (ret != ILB_STATUS_OK) {
1433 free(data.sg_data);
1434 goto out;
1436 assert(data.sg_data != NULL);
1437 /* set sg name */
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) {
1443 free(data.sg_data);
1444 goto out;
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) {
1462 free(data.sg_data);
1463 goto out;
1465 free(data.sg_data);
1468 break;
1469 case ILBD_SCF_HC:
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;
1476 goto out;
1478 ret = ilbd_scf_pg_walk_props(newpg,
1479 ilbd_scf_load_prop, &data);
1480 if (ret != ILB_STATUS_OK)
1481 goto out;
1482 assert(data.hc_data != NULL);
1483 /* set hc name */
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);
1488 free(data.hc_data);
1489 if (ret != ILB_STATUS_OK)
1490 goto out;
1492 break;
1496 out:
1497 free(pg_name);
1498 if (scf_ret < 0)
1499 ret = ilbd_scf_err_to_ilb_err();
1500 scf_pg_destroy(newpg);
1501 scf_iter_destroy(pgiter);
1502 return (ret);
1505 typedef ilb_status_t (*ilbd_scf_walker_fn)(void *, int, struct passwd *,
1506 ucred_t *);
1508 ilb_status_t
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;
1513 scf_handle_t *h;
1514 scf_service_t *svc;
1515 ilb_status_t ret;
1517 ret = ilbd_scf_get_inst(&h, &svc, &inst);
1518 if (ret != ILB_STATUS_OK)
1519 return (ret);
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);
1525 return (ret);
1528 ilb_status_t
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;
1533 scf_handle_t *h;
1534 scf_service_t *svc;
1535 ilb_status_t ret;
1537 ret = ilbd_scf_get_inst(&h, &svc, &inst);
1538 if (ret != ILB_STATUS_OK)
1539 return (ret);
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);
1544 return (ret);
1547 ilb_status_t
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;
1552 scf_handle_t *h;
1553 scf_service_t *svc;
1554 ilb_status_t ret;
1556 ret = ilbd_scf_get_inst(&h, &svc, &inst);
1557 if (ret != ILB_STATUS_OK)
1558 return (ret);
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);
1563 return (ret);
1566 ilb_status_t
1567 ilbd_change_prop(ilbd_scf_pg_type_t pg_type, const char *pg_name,
1568 const char *prop_name, void *new_val)
1570 int ret;
1571 scf_propertygroup_t *scfpg = NULL;
1572 char *scf_pgname = NULL;
1573 scf_type_t scftype;
1574 scf_value_t *scfval;
1575 scf_handle_t *h;
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);
1581 free(scf_pgname);
1583 if (ret != ILB_STATUS_EEXIST)
1584 return (ret);
1586 assert(scfpg != NULL);
1588 h = scf_pg_handle(scfpg);
1589 if (h == NULL) {
1590 ret = ILB_STATUS_EINVAL;
1591 goto done;
1594 if ((scfval = scf_value_create(h)) == NULL) {
1595 ret = ILB_STATUS_ENOMEM;
1596 goto done;
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);
1608 done:
1609 if (scf_pg_handle(scfpg) != NULL)
1610 scf_handle_destroy(scf_pg_handle(scfpg));
1611 if (scfpg != NULL)
1612 scf_pg_destroy(scfpg);
1613 if (scfval != NULL)
1614 scf_value_destroy(scfval);
1615 return (ret);
1619 * Update the persistent configuration with a new server, srv, added to a
1620 * server group, sg.
1622 ilb_status_t
1623 ilbd_scf_add_srv(ilbd_sg_t *sg, ilbd_srv_t *srv)
1625 scf_propertygroup_t *pg;
1626 scf_handle_t *h;
1627 scf_value_t *val;
1628 ilb_status_t ret;
1629 int scf_name_len = ILBD_MAX_NAME_LEN;
1630 char *buf = NULL;
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);
1646 free(buf);
1647 return (ILB_STATUS_INTERNAL);
1650 if ((h = scf_pg_handle(pg)) == NULL) {
1651 ilbd_scf_destroy(NULL, NULL, NULL, pg);
1652 free(buf);
1653 return (ilbd_scf_err_to_ilb_err());
1656 if ((val = scf_value_create(h)) == NULL) {
1657 ilbd_scf_destroy(h, NULL, NULL, pg);
1658 free(buf);
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);
1666 free(buf);
1667 ilbd_scf_destroy(h, NULL, NULL, pg);
1668 scf_value_destroy(val);
1670 return (ret);
1674 * Delete a server, srv, of a server group, sg, from the persistent
1675 * configuration.
1677 ilb_status_t
1678 ilbd_scf_del_srv(ilbd_sg_t *sg, ilbd_srv_t *srv)
1680 ilb_status_t ret;
1681 scf_propertygroup_t *pg;
1682 scf_handle_t *h;
1683 int scf_name_len = ILBD_MAX_NAME_LEN;
1684 char *buf;
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
1695 * maintenance mode.
1697 if (ret != ILB_STATUS_EEXIST) {
1698 free(buf);
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);
1707 free(buf);
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();
1716 goto out;
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();
1725 goto out;
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();
1731 goto out;
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();
1739 out:
1740 free(buf);
1741 if (entry != NULL)
1742 scf_entry_destroy(entry);
1743 if (tx != NULL)
1744 scf_transaction_destroy(tx);
1745 ilbd_scf_destroy(h, NULL, NULL, pg);
1747 return (ret);