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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
44 static ilbadm_key_name_t servrange_keys
[] = {
45 {ILB_KEY_SERVER
, "server", "servers"},
46 {ILB_KEY_SERVRANGE
, "server", "servers"},
50 static ilbadm_key_name_t serverID_keys
[] = {
51 {ILB_KEY_SERVERID
, "server", ""},
55 typedef struct sg_export_arg
{
60 typedef struct arg_struct
{
63 ofmt_field_t
*o_fields
;
67 typedef struct sg_srv_o_struct
{
69 ilb_server_data_t
*sd
;
72 static ofmt_cb_t of_sgname
;
73 static ofmt_cb_t of_srvID
;
74 static ofmt_cb_t of_port
;
75 static ofmt_cb_t of_ip
;
77 static ofmt_field_t sgfields_v4
[] = {
78 {"SGNAME", ILB_SGNAME_SZ
, 0, of_sgname
},
79 {"SERVERID", ILB_NAMESZ
, 0, of_srvID
},
80 {"MINPORT", 8, 0, of_port
},
81 {"MAXPORT", 8, 1, of_port
},
82 {"IP_ADDRESS", 15, 0, of_ip
},
85 static ofmt_field_t sgfields_v6
[] = {
86 {"SGNAME", ILB_SGNAME_SZ
, 0, of_sgname
},
87 {"SERVERID", ILB_NAMESZ
, 0, of_srvID
},
88 {"MINPORT", 8, 0, of_port
},
89 {"MAXPORT", 8, 1, of_port
},
90 {"IP_ADDRESS", 39, 0, of_ip
},
94 #define MAXCOLS 80 /* make flexible? */
96 extern int optind
, optopt
, opterr
;
100 of_sgname(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
102 sg_srv_o_arg_t
*l
= (sg_srv_o_arg_t
*)of_arg
->ofmt_cbarg
;
104 (void) strlcpy(buf
, l
->sgname
, bufsize
);
109 of_srvID(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
111 sg_srv_o_arg_t
*l
= (sg_srv_o_arg_t
*)of_arg
->ofmt_cbarg
;
113 (void) strlcpy(buf
, l
->sd
->sd_srvID
, bufsize
);
118 of_port(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
120 sg_srv_o_arg_t
*l
= (sg_srv_o_arg_t
*)of_arg
->ofmt_cbarg
;
123 if (of_arg
->ofmt_id
== 0) {
124 port
= ntohs(l
->sd
->sd_minport
);
128 (void) snprintf(buf
, bufsize
, "%d", port
);
130 port
= ntohs(l
->sd
->sd_maxport
);
134 (void) snprintf(buf
, bufsize
, "%d", port
);
140 of_ip(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
142 sg_srv_o_arg_t
*l
= (sg_srv_o_arg_t
*)of_arg
->ofmt_cbarg
;
144 ip2str(&l
->sd
->sd_addr
, buf
, bufsize
, V6_ADDRONLY
);
149 i_list_sg_srv_ofmt(char *sgname
, ilb_server_data_t
*sd
, void *arg
)
151 list_arg_t
*larg
= (list_arg_t
*)arg
;
152 sg_srv_o_arg_t line_arg
;
154 line_arg
.sgname
= sgname
;
156 ofmt_print(larg
->oh
, &line_arg
);
161 * This function is always called via ilb_walk_servergroups()
162 * and so must return libilb errors.
163 * That's why we need to retain currently unused "h" argument
167 ilbadm_list_sg_srv(ilb_handle_t h
, ilb_server_data_t
*sd
, const char *sgname
,
170 char ip_str
[2*INET6_ADDRSTRLEN
+ 3] = "";
171 char port_str
[INET6_ADDRSTRLEN
];
172 list_arg_t
*larg
= (list_arg_t
*)arg
;
176 int h_minport
, h_maxport
;
177 static ofmt_handle_t oh
= (ofmt_handle_t
)NULL
;
180 if (larg
->o_str
!= NULL
) {
182 if (sd
->sd_addr
.ia_af
== AF_INET
)
187 if (larg
->flags
& ILBADM_LIST_PARSE
)
188 oflags
|= OFMT_PARSABLE
;
190 oerr
= ofmt_open(larg
->o_str
, ofp
, oflags
, ocols
, &oh
);
191 if (oerr
!= OFMT_SUCCESS
) {
194 ilbadm_err(gettext("ofmt_open failed: %s"),
195 ofmt_strerror(oh
, oerr
, e
, sizeof (e
)));
196 return (ILB_STATUS_GENERIC
);
202 (void) i_list_sg_srv_ofmt((char *)sgname
, sd
, arg
);
203 return (ILB_STATUS_OK
);
206 ip2str(&sd
->sd_addr
, ip_str
, sizeof (ip_str
), 0);
208 h_minport
= ntohs(sd
->sd_minport
);
209 h_maxport
= ntohs(sd
->sd_maxport
);
212 else if (h_maxport
> h_minport
)
213 (void) sprintf(port_str
, ":%d-%d", h_minport
, h_maxport
);
215 (void) sprintf(port_str
, ":%d", h_minport
);
217 (void) printf("%s: id:%s %s%s\n", sgname
,
218 sd
->sd_srvID
?sd
->sd_srvID
:"(null)", ip_str
, port_str
);
219 return (ILB_STATUS_OK
);
223 ilbadm_list_sg(ilb_handle_t h
, ilb_sg_data_t
*sg
, void *arg
)
225 if (sg
->sgd_srvcount
== 0) {
226 ilb_server_data_t tmp_srv
;
228 bzero(&tmp_srv
, sizeof (tmp_srv
));
229 return (ilbadm_list_sg_srv(h
, &tmp_srv
, sg
->sgd_name
, arg
));
232 return (ilb_walk_servers(h
, ilbadm_list_sg_srv
, sg
->sgd_name
, arg
));
235 static char *def_fields
= "SGNAME,SERVERID,MINPORT,MAXPORT,IP_ADDRESS";
239 ilbadm_show_servergroups(int argc
, char *argv
[])
241 ilb_handle_t h
= ILB_INVALID_HANDLE
;
242 ilb_status_t rclib
= ILB_STATUS_OK
;
243 ilbadm_status_t rc
= ILBADM_OK
;
245 char optstr
[] = ":po:";
247 boolean_t o_opt
= B_FALSE
, p_opt
= B_FALSE
;
248 list_arg_t larg
= {0, def_fields
, NULL
, NULL
};
250 while ((c
= getopt(argc
, argv
, optstr
)) != -1) {
252 case 'p': p_opt
= B_TRUE
;
253 larg
.flags
|= ILBADM_LIST_PARSE
;
255 case 'o': larg
.o_str
= optarg
;
258 case ':': ilbadm_err(gettext("missing option argument"
259 " for %c"), (char)optopt
);
262 default: unknown_opt(argv
, optind
-1);
268 if (p_opt
&& !o_opt
) {
269 ilbadm_err(gettext("option -p requires -o"));
273 if (p_opt
&& larg
.o_str
!= NULL
&&
274 (strcasecmp(larg
.o_str
, "all") == 0)) {
275 ilbadm_err(gettext("option -p requires explicit field"
280 rclib
= ilb_open(&h
);
281 if (rclib
!= ILB_STATUS_OK
)
284 if (optind
>= argc
) {
285 rclib
= ilb_walk_servergroups(h
, ilbadm_list_sg
, NULL
,
287 if (rclib
!= ILB_STATUS_OK
)
290 while (optind
< argc
) {
291 rclib
= ilb_walk_servergroups(h
, ilbadm_list_sg
,
292 argv
[optind
++], (void*)&larg
);
293 if (rclib
!= ILB_STATUS_OK
) {
303 if (h
!= ILB_INVALID_HANDLE
)
306 if (rclib
!= ILB_STATUS_OK
) {
308 * The show function returns ILB_STATUS_GENERIC after printing
309 * out an error message. So we don't need to print it again.
311 if (rclib
!= ILB_STATUS_GENERIC
)
312 ilbadm_err(ilb_errstr(rclib
));
320 i_new_sg_elem(ilbadm_sgroup_t
*sgp
)
322 ilbadm_servnode_t
*s
;
324 s
= (ilbadm_servnode_t
*)calloc(sizeof (*s
), 1);
326 list_insert_tail(&sgp
->sg_serv_list
, s
);
332 static ilbadm_status_t
333 i_parse_servrange_list(char *arg
, ilbadm_sgroup_t
*sgp
)
338 rc
= i_parse_optstring(arg
, (void *) sgp
, servrange_keys
,
339 OPT_VALUE_LIST
|OPT_IP_RANGE
|OPT_PORTS
, &count
);
343 static ilbadm_status_t
344 i_parse_serverIDs(char *arg
, ilbadm_sgroup_t
*sgp
)
349 rc
= i_parse_optstring(arg
, (void *) sgp
, serverID_keys
,
350 OPT_VALUE_LIST
|OPT_PORTS
, &count
);
354 static ilbadm_status_t
355 i_mod_sg(ilb_handle_t h
, ilbadm_sgroup_t
*sgp
, ilbadm_cmd_t cmd
,
358 ilbadm_servnode_t
*sn
;
359 ilb_server_data_t
*srv
;
360 ilb_status_t rclib
= ILB_STATUS_OK
;
361 ilbadm_status_t rc
= ILBADM_OK
;
363 if (h
== ILB_INVALID_HANDLE
&& cmd
!= cmd_enable_server
&&
364 cmd
!= cmd_disable_server
)
365 return (ILBADM_LIBERR
);
367 sn
= list_head(&sgp
->sg_serv_list
);
371 srv
->sd_flags
|= flags
;
372 if (cmd
== cmd_create_sg
|| cmd
== cmd_add_srv
) {
373 rclib
= ilb_add_server_to_group(h
, sgp
->sg_name
,
375 if (rclib
!= ILB_STATUS_OK
) {
376 char buf
[INET6_ADDRSTRLEN
+ 1];
379 ip2str(&srv
->sd_addr
, buf
, sizeof (buf
),
381 ilbadm_err(gettext("cannot add %s to %s: %s"),
382 buf
, sgp
->sg_name
, ilb_errstr(rclib
));
383 /* if we created the SG, we bail out */
384 if (cmd
== cmd_create_sg
)
388 assert(cmd
== cmd_rem_srv
);
389 rclib
= ilb_rem_server_from_group(h
, sgp
->sg_name
,
391 /* if we fail, we tell user and continue */
392 if (rclib
!= ILB_STATUS_OK
) {
395 gettext("cannot remove %s from %s: %s"),
396 srv
->sd_srvID
, sgp
->sg_name
,
402 * list_next returns NULL instead of cycling back to head
403 * so we don't have to check for list_head explicitly.
405 sn
= list_next(&sgp
->sg_serv_list
, sn
);
412 i_ilbadm_alloc_sgroup(ilbadm_sgroup_t
**sgp
)
416 *sgp
= sg
= (ilbadm_sgroup_t
*)calloc(sizeof (*sg
), 1);
419 list_create(&sg
->sg_serv_list
, sizeof (ilbadm_servnode_t
),
420 offsetof(ilbadm_servnode_t
, s_link
));
424 i_ilbadm_free_sgroup(ilbadm_sgroup_t
*sg
)
426 ilbadm_servnode_t
*s
;
428 while ((s
= list_remove_head(&sg
->sg_serv_list
)) != NULL
)
431 list_destroy(&sg
->sg_serv_list
);
435 ilbadm_create_servergroup(int argc
, char *argv
[])
437 ilb_handle_t h
= ILB_INVALID_HANDLE
;
438 ilb_status_t rclib
= ILB_STATUS_OK
;
439 ilbadm_status_t rc
= ILBADM_OK
;
444 i_ilbadm_alloc_sgroup(&sg
);
446 while ((c
= getopt(argc
, argv
, ":s:")) != -1) {
449 rc
= i_parse_servrange_list(optarg
, sg
);
452 ilbadm_err(gettext("missing option-argument for"
453 " %c"), (char)optopt
);
458 unknown_opt(argv
, optind
-1);
467 if (optind
>= argc
) {
468 ilbadm_err(gettext("missing mandatory arguments - please refer"
469 " to 'create-servergroup' subcommand"
470 " description in ilbadm(1M)"));
475 if (strlen(argv
[optind
]) > ILB_SGNAME_SZ
- 1) {
476 ilbadm_err(gettext("servergroup name %s is too long -"
477 " must not exceed %d chars"), argv
[optind
],
483 sg
->sg_name
= argv
[optind
];
485 rclib
= ilb_open(&h
);
486 if (rclib
!= ILB_STATUS_OK
)
489 rclib
= ilb_create_servergroup(h
, sg
->sg_name
);
490 if (rclib
!= ILB_STATUS_OK
)
493 /* we create a servergroup with all servers enabled */
494 ILB_SET_ENABLED(flags
);
495 rc
= i_mod_sg(h
, sg
, cmd_create_sg
, flags
);
498 (void) ilb_destroy_servergroup(h
, sg
->sg_name
);
501 i_ilbadm_free_sgroup(sg
);
502 if (h
!= ILB_INVALID_HANDLE
)
505 if (rclib
!= ILB_STATUS_OK
) {
506 ilbadm_err(ilb_errstr(rclib
));
509 if ((rc
!= ILBADM_OK
) && (rc
!= ILBADM_LIBERR
))
510 ilbadm_err(ilbadm_errstr(rc
));
516 ilbadm_add_server_to_group(int argc
, char **argv
)
518 ilb_handle_t h
= ILB_INVALID_HANDLE
;
519 ilb_status_t rclib
= ILB_STATUS_OK
;
520 ilbadm_status_t rc
= ILBADM_OK
;
525 i_ilbadm_alloc_sgroup(&sg
);
527 while ((c
= getopt(argc
, argv
, ":s:")) != -1) {
530 rc
= i_parse_servrange_list(optarg
, sg
);
533 ilbadm_err(gettext("missing option-argument for"
534 " %c"), (char)optopt
);
538 default: unknown_opt(argv
, optind
-1);
547 if (optind
>= argc
) {
548 ilbadm_err(gettext("missing mandatory arguments - please refer"
549 " to 'add-server' subcommand description in ilbadm(1M)"));
554 sg
->sg_name
= argv
[optind
];
556 rclib
= ilb_open(&h
);
557 if (rclib
!= ILB_STATUS_OK
)
560 /* A server is added enabled */
561 ILB_SET_ENABLED(flags
);
562 rc
= i_mod_sg(h
, sg
, cmd_add_srv
, flags
);
564 i_ilbadm_free_sgroup(sg
);
565 if (h
!= ILB_INVALID_HANDLE
)
568 if ((rc
!= ILBADM_OK
) && (rc
!= ILBADM_LIBERR
))
569 ilbadm_err(ilbadm_errstr(rc
));
574 static ilbadm_status_t
575 ilbadm_Xable_server(int argc
, char *argv
[], ilbadm_cmd_t cmd
)
577 ilb_handle_t h
= ILB_INVALID_HANDLE
;
578 ilbadm_status_t rc
= ILBADM_OK
;
579 ilb_status_t rclib
= ILB_STATUS_OK
;
583 ilbadm_err(gettext("missing required argument"
584 " (server specification)"));
589 rclib
= ilb_open(&h
);
590 if (rclib
!= ILB_STATUS_OK
)
593 /* enable-server and disable-server only accepts serverids */
594 for (i
= 1; i
< argc
&& rclib
== ILB_STATUS_OK
; i
++) {
595 ilb_server_data_t srv
;
597 if (argv
[i
][0] != ILB_SRVID_PREFIX
) {
598 rc
= ILBADM_INVAL_SRVID
;
602 bzero(&srv
, sizeof (srv
));
603 /* to do: check length */
604 (void) strlcpy(srv
.sd_srvID
, argv
[i
], sizeof (srv
.sd_srvID
));
606 case cmd_enable_server
:
607 rclib
= ilb_enable_server(h
, &srv
, NULL
);
609 case cmd_disable_server
:
610 rclib
= ilb_disable_server(h
, &srv
, NULL
);
614 /* if we can't find a given server ID, just plough on */
615 if (rclib
== ILB_STATUS_ENOENT
) {
616 const char *msg
= ilb_errstr(rclib
);
619 ilbadm_err("%s: %s", msg
, argv
[i
]);
620 rclib
= ILB_STATUS_OK
;
623 if (rclib
!= ILB_STATUS_OK
)
627 if (h
!= ILB_INVALID_HANDLE
)
630 if (rclib
!= ILB_STATUS_OK
) {
631 ilbadm_err(ilb_errstr(rclib
));
635 if ((rc
!= ILBADM_OK
) && (rc
!= ILBADM_LIBERR
))
636 ilbadm_err(ilbadm_errstr(rc
));
641 ilbadm_disable_server(int argc
, char *argv
[])
643 return (ilbadm_Xable_server(argc
, argv
, cmd_disable_server
));
647 ilbadm_enable_server(int argc
, char *argv
[])
649 return (ilbadm_Xable_server(argc
, argv
, cmd_enable_server
));
654 ilbadm_rem_server_from_group(int argc
, char *argv
[])
656 ilb_handle_t h
= ILB_INVALID_HANDLE
;
657 ilb_status_t rclib
= ILB_STATUS_OK
;
658 ilbadm_status_t rc
= ILBADM_OK
;
662 i_ilbadm_alloc_sgroup(&sg
);
664 while ((c
= getopt(argc
, argv
, ":s:")) != -1) {
667 rc
= i_parse_serverIDs(optarg
, sg
);
670 ilbadm_err(gettext("missing option-argument for"
671 " %c"), (char)optopt
);
675 default: unknown_opt(argv
, optind
-1);
683 /* we need servergroup name and at least one serverID to remove */
684 if (optind
>= argc
|| sg
->sg_count
== 0) {
685 rc
= ILBADM_ENOOPTION
;
689 sg
->sg_name
= argv
[optind
];
691 rclib
= ilb_open(&h
);
692 if (rclib
!= ILB_STATUS_OK
)
695 rc
= i_mod_sg(h
, sg
, cmd_rem_srv
, 0);
697 i_ilbadm_free_sgroup(sg
);
699 if (h
!= ILB_INVALID_HANDLE
)
701 if ((rc
!= ILBADM_OK
) && (rc
!= ILBADM_LIBERR
))
702 ilbadm_err(ilbadm_errstr(rc
));
707 ilbadm_destroy_servergroup(int argc
, char *argv
[])
709 ilb_handle_t h
= ILB_INVALID_HANDLE
;
710 ilb_status_t rclib
= ILB_STATUS_OK
;
711 ilbadm_status_t rc
= ILBADM_OK
;
715 ilbadm_err(gettext("usage:ilbadm"
716 " delete-servergroup groupname"));
723 rclib
= ilb_open(&h
);
724 if (rclib
!= ILB_STATUS_OK
)
727 rclib
= ilb_destroy_servergroup(h
, sgname
);
729 if (h
!= ILB_INVALID_HANDLE
)
732 if (rclib
!= ILB_STATUS_OK
) {
733 ilbadm_err(ilb_errstr(rclib
));
743 export_srv_spec(ilb_server_data_t
*srv
, char *buf
, const int bufsize
)
745 int len
= 0, bufsz
= (int)bufsize
;
747 ip2str(&srv
->sd_addr
, buf
, bufsz
, 0);
752 if (srv
->sd_minport
!= 0) {
753 in_port_t h_min
, h_max
;
756 h_min
= ntohs(srv
->sd_minport
);
757 h_max
= ntohs(srv
->sd_maxport
);
759 /* to do: if service name was given, print that, not number */
761 inc
= snprintf(buf
+len
, bufsz
, ":%d", h_min
);
763 inc
= snprintf(buf
+len
, bufsz
, ":%d-%d", h_min
, h_max
);
765 if (inc
> bufsz
) /* too little space */
775 * this is called by ilb_walk_servers(), therefore we return ilb_status_t
776 * not ilbadm_status, and retain an unused function argument
780 ilbadm_export_a_srv(ilb_handle_t h
, ilb_server_data_t
*srv
, const char *sgname
,
783 sg_export_arg_t
*larg
= (sg_export_arg_t
*)arg
;
785 char linebuf
[BUFSZ
]; /* XXXms make that dynamic */
788 if (export_srv_spec(srv
, linebuf
, sz
) == -1)
789 return (ILB_STATUS_OK
);
791 (void) fprintf(fp
, "add-server -s server=");
793 (void) fprintf(fp
, "%s %s\n", linebuf
, sgname
);
794 return (ILB_STATUS_OK
);
798 ilbadm_export_sg(ilb_handle_t h
, ilb_sg_data_t
*sg
, void *arg
)
800 ilb_status_t rc
= ILB_STATUS_OK
;
801 sg_export_arg_t
*larg
= (sg_export_arg_t
*)arg
;
804 (void) fprintf(fp
, "create-servergroup %s\n", sg
->sgd_name
);
805 if (sg
->sgd_srvcount
== 0)
806 return (ILB_STATUS_OK
);
808 rc
= ilb_walk_servers(h
, ilbadm_export_a_srv
, sg
->sgd_name
, arg
);
809 if (rc
!= ILB_STATUS_OK
)
812 if (fflush(fp
) == EOF
)
813 rc
= ILB_STATUS_WRITE
;
820 ilbadm_export_servergroups(ilb_handle_t h
, FILE *fp
)
822 ilb_status_t rclib
= ILB_STATUS_OK
;
823 ilbadm_status_t rc
= ILBADM_OK
;
829 rclib
= ilb_walk_servergroups(h
, ilbadm_export_sg
, NULL
, (void *)&arg
);
830 if (rclib
!= ILB_STATUS_OK
) {
831 ilbadm_err(ilb_errstr(rclib
));