dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / ilbadm / ilbadm_rules.c
blobf159a3b6d69902afd6729a991c2f9a6cc9ab3b2e
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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <strings.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <sys/list.h>
38 #include <netdb.h>
39 #include <ofmt.h>
40 #include <assert.h>
41 #include <libilb.h>
42 #include "ilbadm.h"
44 static ilbadm_key_name_t rl_incoming_keys[] = {
45 {ILB_KEY_VIP, "vip", ""},
46 {ILB_KEY_PORT, "port", ""},
47 {ILB_KEY_PROTOCOL, "protocol", "prot"},
48 {ILB_KEY_BAD, "", ""}
50 static ilbadm_key_name_t rl_method_keys[] = {
51 {ILB_KEY_ALGORITHM, "lbalg", "algo"},
52 {ILB_KEY_TYPE, "type", "topo"},
53 {ILB_KEY_SRC, "proxy-src", "nat-src"},
54 {ILB_KEY_STICKY, "pmask", "persist"},
55 {ILB_KEY_BAD, "", ""}
57 static ilbadm_key_name_t rl_outgoing_keys[] = {
58 {ILB_KEY_SERVERGROUP, "servergroup", "sg"},
59 {ILB_KEY_BAD, "", ""}
61 static ilbadm_key_name_t rl_healthchk_keys[] = {
62 {ILB_KEY_HEALTHCHECK, "hc-name", "hcn"},
63 {ILB_KEY_HCPORT, "hc-port", "hcp"},
64 {ILB_KEY_BAD, "", ""}
66 static ilbadm_key_name_t rl_timer_keys[] = {
67 {ILB_KEY_CONNDRAIN, "conn-drain", ""},
68 {ILB_KEY_NAT_TO, "nat-timeout", ""},
69 {ILB_KEY_STICKY_TO, "persist-timeout", ""},
70 {ILB_KEY_BAD, "", ""}
73 static ilbadm_key_name_t *all_keys[] = {
74 rl_incoming_keys, rl_method_keys, rl_outgoing_keys,
75 rl_healthchk_keys, rl_timer_keys, NULL
79 /* field ids for of_* functions */
80 #define OF_IP_VIP 0
81 #define OF_IP_PROXYSRC 1
82 #define OF_IP_STICKYMASK 2
84 #define OF_STR_RNAME 0
85 #define OF_STR_HCNAME 1
86 #define OF_STR_SGNAME 2
87 #define OF_STR_INTERFACE 3
89 #define OF_PORT 0
90 #define OF_HCPORT 1
92 #define OF_T_CONN 0
93 #define OF_T_NAT 1
94 #define OF_T_STICKY 2
96 #define OF_SRV_ID 0
97 #define OF_SRV_ADDR 1
98 #define OF_SRV_PORT 2
99 #define OF_SRV_STATUS 3
100 #define OF_SRV_RNAME 4
101 #define OF_SRV_SGNAME 5
102 #define OF_SRV_HOSTNAME 6
104 /* some field sizes of ofmt_field_t arrays */
105 #define IPv4_FIELDWIDTH 16
106 #define IPv6_FIELDWIDTH 39
107 #define ILB_HOSTNAMELEN 20
108 #define ILB_STATUSFIELD_LEN 7
110 typedef struct arg_struct {
111 int flags;
112 char *o_str;
113 ofmt_field_t *o_fields;
114 ofmt_handle_t oh;
115 } ilbadm_sh_rl_arg_t;
117 typedef struct ilbadm_rl_exp_arg {
118 FILE *fp;
119 } ilbadm_rl_exp_arg_t;
121 typedef struct ilbadm_rl_list_arg {
122 ilb_handle_t h;
123 ilb_rule_data_t *rd;
124 } ilbadm_rl_list_arg_t;
126 typedef struct ilbadm_rl_srvlist_arg {
127 char *sgname;
128 ilb_server_data_t *sd;
129 ilb_rule_data_t *rd;
130 int flags;
131 char *o_str;
132 ofmt_field_t *o_fields;
133 ofmt_handle_t oh;
134 } ilbadm_rl_srvlist_arg_t;
136 static ofmt_cb_t of_algo;
137 static ofmt_cb_t of_proto;
138 static ofmt_cb_t of_rl_ip;
139 static ofmt_cb_t of_rl_mask;
140 static ofmt_cb_t of_rport;
141 static ofmt_cb_t of_rstatus;
142 static ofmt_cb_t of_str;
143 static ofmt_cb_t of_time;
144 static ofmt_cb_t of_topo;
145 static ofmt_cb_t of_rl_srvlist;
147 static boolean_t of_srv2str(ofmt_arg_t *, char *, uint_t);
148 static boolean_t of_port2str(in_port_t, in_port_t, char *, uint_t);
150 static ofmt_field_t rfields_v4[] = {
151 {"RULENAME", ILB_NAMESZ, OF_STR_RNAME, of_str},
152 {"STATUS", ILB_STATUSFIELD_LEN, 0, of_rstatus},
153 {"PORT", 10, OF_PORT, of_rport},
154 {"PROTOCOL", 5, 0, of_proto},
155 {"LBALG", 12, 0, of_algo},
156 {"TYPE", 8, 0, of_topo},
157 {"PROXY-SRC", 2*IPv4_FIELDWIDTH+1, OF_IP_PROXYSRC, of_rl_ip},
158 {"PMASK", 6, OF_IP_STICKYMASK, of_rl_mask},
159 {"HC-NAME", ILB_NAMESZ, OF_STR_HCNAME, of_str},
160 {"HC-PORT", 8, OF_HCPORT, of_rport},
161 {"CONN-DRAIN", 11, OF_T_CONN, of_time},
162 {"NAT-TIMEOUT", 12, OF_T_NAT, of_time},
163 {"PERSIST-TIMEOUT", 16, OF_T_STICKY, of_time},
164 {"SERVERGROUP", ILB_SGNAME_SZ, OF_STR_SGNAME, of_str},
165 {"VIP", IPv4_FIELDWIDTH, OF_IP_VIP, of_rl_ip},
166 {"SERVERS", 20, 0, of_rl_srvlist},
167 {NULL, 0, 0, NULL}
170 static ofmt_field_t rfields_v6[] = {
171 {"RULENAME", ILB_NAMESZ, OF_STR_RNAME, of_str},
172 {"STATUS", ILB_STATUSFIELD_LEN, 0, of_rstatus},
173 {"PORT", 10, OF_PORT, of_rport},
174 {"PROTOCOL", 5, 0, of_proto},
175 {"LBALG", 12, 0, of_algo},
176 {"TYPE", 8, 0, of_topo},
177 {"PROXY-SRC", IPv6_FIELDWIDTH, OF_IP_PROXYSRC, of_rl_ip},
178 {"PMASK", 6, OF_IP_STICKYMASK, of_rl_mask},
179 {"HC-NAME", ILB_NAMESZ, OF_STR_HCNAME, of_str},
180 {"HC-PORT", 8, OF_HCPORT, of_rport},
181 {"CONN-DRAIN", 11, OF_T_CONN, of_time},
182 {"NAT-TIMEOUT", 12, OF_T_NAT, of_time},
183 {"PERSIST-TIMEOUT", 16, OF_T_STICKY, of_time},
184 {"SERVERGROUP", ILB_SGNAME_SZ, OF_STR_SGNAME, of_str},
185 {"VIP", IPv6_FIELDWIDTH, OF_IP_VIP, of_rl_ip},
186 {"SERVERS", 20, 0, of_rl_srvlist},
187 {NULL, 0, 0, NULL}
190 static ofmt_field_t ssfields_v4[] = {
191 {"SERVERID", ILB_NAMESZ, OF_SRV_ID, of_srv2str},
192 {"ADDRESS", IPv4_FIELDWIDTH, OF_SRV_ADDR, of_srv2str},
193 {"PORT", 5, OF_SRV_PORT, of_srv2str},
194 {"RULENAME", ILB_NAMESZ, OF_SRV_RNAME, of_srv2str},
195 {"STATUS", ILB_STATUSFIELD_LEN, OF_SRV_STATUS, of_srv2str},
196 {"SERVERGROUP", ILB_SGNAME_SZ, OF_SRV_SGNAME, of_srv2str},
197 {"HOSTNAME", ILB_HOSTNAMELEN, OF_SRV_HOSTNAME, of_srv2str},
198 {NULL, 0, 0, NULL}
201 static ofmt_field_t ssfields_v6[] = {
202 {"SERVERID", ILB_NAMESZ, OF_SRV_ID, of_srv2str},
203 {"ADDRESS", IPv6_FIELDWIDTH, OF_SRV_ADDR, of_srv2str},
204 {"PORT", 5, OF_SRV_PORT, of_srv2str},
205 {"RULENAME", ILB_NAMESZ, OF_SRV_RNAME, of_srv2str},
206 {"STATUS", ILB_STATUSFIELD_LEN, OF_SRV_STATUS, of_srv2str},
207 {"SERVERGROUP", ILB_SGNAME_SZ, OF_SRV_SGNAME, of_srv2str},
208 {"HOSTNAME", ILB_HOSTNAMELEN, OF_SRV_HOSTNAME, of_srv2str},
209 {NULL, 0, 0, NULL}
212 extern int optind, optopt, opterr;
213 extern char *optarg;
215 extern ilbadm_val_type_t algo_types[];
216 extern ilbadm_val_type_t topo_types[];
218 static char *
219 i_key_to_opt(ilbadm_key_name_t *n, ilbadm_key_code_t k)
221 int i;
223 for (i = 0; n[i].k_key != ILB_KEY_BAD; i++)
224 if (n[i].k_key == k)
225 break;
227 return (n[i].k_name);
230 char *
231 ilbadm_key_to_opt(ilbadm_key_code_t k)
233 char *name;
234 int i;
236 for (i = 0; all_keys[i] != NULL; i++) {
237 name = i_key_to_opt(all_keys[i], k);
238 if (*name != '\0')
239 return (name);
242 return (NULL);
246 * ports are in HOST byte order
248 static void
249 ports2str(short port1, short port2, char *buf, const int sz)
251 if (port2 <= port1)
252 (void) snprintf(buf, sz, "port=%d", port1);
253 else
254 (void) snprintf(buf, sz, "port=%d-%d", port1, port2);
257 static void
258 proto2str(short proto, char *buf, int sz)
260 struct protoent *pe;
262 pe = getprotobynumber((int)proto);
263 if (pe != NULL)
264 (void) snprintf(buf, sz, "protocol=%s", pe->p_name);
265 else
266 (void) sprintf(buf, "(bad proto %d)", proto);
269 static void
270 algo2str(ilb_algo_t algo, char *buf, int sz)
272 char *s = i_str_from_val((int)algo, &algo_types[0]);
274 (void) snprintf(buf, sz, "lbalg=%s", (s && *s) ? s : "(bad algo)");
277 static int
278 algo2bare_str(ilb_algo_t algo, char *buf, int sz)
280 char *s = i_str_from_val((int)algo, &algo_types[0]);
282 return (snprintf(buf, sz, "%s", (s && *s) ? s : ""));
285 static void
286 topo2str(ilb_topo_t topo, char *buf, int sz)
288 char *s = i_str_from_val((int)topo, &topo_types[0]);
290 (void) snprintf(buf, sz, "type=%s", (s && *s) ? s : "(bad type)");
293 static int
294 topo2bare_str(ilb_topo_t topo, char *buf, int sz)
296 char *s = i_str_from_val((int)topo, &topo_types[0]);
298 return (snprintf(buf, sz, "%s", (s && *s) ? s : ""));
301 static boolean_t
302 of_str(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
304 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
305 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
307 switch (of_arg->ofmt_id) {
308 case OF_STR_RNAME:
309 (void) strlcpy(buf, rd->r_name, bufsize);
310 break;
311 case OF_STR_SGNAME:
312 (void) strlcpy(buf, rd->r_sgname, bufsize);
313 break;
314 case OF_STR_HCNAME:
315 if (rd->r_hcname != NULL && *(rd->r_hcname) != '\0')
316 (void) strlcpy(buf, rd->r_hcname, bufsize);
317 break;
319 return (B_TRUE);
322 /* ARGSUSED */
323 static boolean_t
324 of_proto(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
326 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
327 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
329 if (rd->r_proto == IPPROTO_TCP)
330 (void) strlcpy(buf, "TCP", bufsize);
331 else if (rd->r_proto == IPPROTO_UDP)
332 (void) strlcpy(buf, "UDP", bufsize);
333 else
334 return (B_FALSE);
335 return (B_TRUE);
338 static boolean_t
339 of_rl_ip(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
341 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
342 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
343 ilb_ip_addr_t *ip = NULL, *ip2 = NULL;
345 switch (of_arg->ofmt_id) {
346 case OF_IP_VIP:
347 ip = &rd->r_vip;
348 break;
349 case OF_IP_PROXYSRC:
350 ip = &rd->r_nat_src_start;
351 ip2 = &rd->r_nat_src_end;
352 break;
353 case OF_IP_STICKYMASK:
354 ip = &rd->r_stickymask;
355 break;
358 /* only print something valid */
359 if (ip != NULL && (ip->ia_af == AF_INET || ip->ia_af == AF_INET6))
360 ip2str(ip, buf, bufsize, V6_ADDRONLY);
361 if (ip2 != NULL && (ip2->ia_af == AF_INET || ip2->ia_af == AF_INET6) &&
362 buf[0] != '\0') {
363 int sl = strlen(buf);
365 buf += sl; bufsize -= sl;
366 *buf++ = '-'; bufsize--;
367 ip2str(ip2, buf, bufsize, V6_ADDRONLY);
370 return (B_TRUE);
373 static boolean_t
374 of_rl_mask(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
376 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
377 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
378 ilb_ip_addr_t *ip = NULL;
380 assert(of_arg->ofmt_id == OF_IP_STICKYMASK);
381 if (!(rd->r_flags & ILB_FLAGS_RULE_STICKY))
382 return (B_TRUE);
383 ip = &rd->r_stickymask;
385 (void) snprintf(buf, bufsize, "/%d", ilbadm_mask_to_prefixlen(ip));
386 return (B_TRUE);
389 static void
390 hcport_print(ilb_rule_data_t *rd, char *buf, uint_t bufsize)
392 if (rd->r_hcport != 0)
393 (void) snprintf(buf, bufsize, "%d", ntohs(rd->r_hcport));
394 else if (rd->r_hcpflag == ILB_HCI_PROBE_ANY)
395 (void) snprintf(buf, bufsize, "ANY");
396 else
397 buf[0] = '\0';
399 static boolean_t
400 of_rport(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
402 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
403 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
405 if (of_arg->ofmt_id == OF_PORT)
406 return (of_port2str(rd->r_minport, rd->r_maxport, buf,
407 bufsize));
409 /* only print a hcport if there's a hc name as well */
410 if (of_arg->ofmt_id == OF_HCPORT && rd->r_hcname[0] != '\0')
411 hcport_print(rd, buf, bufsize);
413 return (B_TRUE);
416 /* ARGSUSED */
417 static boolean_t
418 of_rstatus(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
420 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
421 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
423 if ((rd->r_flags & ILB_FLAGS_RULE_ENABLED) == ILB_FLAGS_RULE_ENABLED)
424 buf[0] = 'E';
425 else
426 buf[0] = 'D';
427 buf[1] = '\0';
428 return (B_TRUE);
431 static boolean_t
432 of_algo(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
434 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
435 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
437 if (algo2bare_str(rd->r_algo, buf, bufsize) == 0)
438 return (B_FALSE);
439 return (B_TRUE);
442 static boolean_t
443 of_topo(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
445 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
446 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
448 if (topo2bare_str(rd->r_topo, buf, bufsize) == 0)
449 return (B_FALSE);
450 return (B_TRUE);
453 static boolean_t
454 of_time(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
456 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
457 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
459 switch (of_arg->ofmt_id) {
460 case OF_T_CONN:
461 (void) snprintf(buf, bufsize, "%u", rd->r_conndrain);
462 break;
463 case OF_T_NAT:
464 (void) snprintf(buf, bufsize, "%u", rd->r_nat_timeout);
465 break;
466 case OF_T_STICKY:
467 (void) snprintf(buf, bufsize, "%u", rd->r_sticky_timeout);
468 break;
470 return (B_TRUE);
473 typedef struct rl_showlist_arg {
474 char *buf;
475 uint_t bufsize;
476 } rl_showlist_arg_t;
478 /* ARGSUSED */
479 /* called by ilb_walk_servers(), cannot get rid of unused args */
480 static ilb_status_t
481 srv2srvID(ilb_handle_t h, ilb_server_data_t *sd, const char *sgname, void *arg)
483 rl_showlist_arg_t *sla = (rl_showlist_arg_t *)arg;
484 int len;
486 (void) snprintf(sla->buf, sla->bufsize, "%s,", sd->sd_srvID);
487 len = strlen(sd->sd_srvID) + 1;
488 sla->buf += len;
489 sla->bufsize -= len;
491 return (ILB_STATUS_OK);
494 static boolean_t
495 of_rl_srvlist(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
497 ilbadm_rl_list_arg_t *ra = (ilbadm_rl_list_arg_t *)of_arg->ofmt_cbarg;
498 ilb_rule_data_t *rd = (ilb_rule_data_t *)ra->rd;
499 rl_showlist_arg_t sla;
501 sla.buf = buf;
502 sla.bufsize = bufsize;
504 (void) ilb_walk_servers(ra->h, srv2srvID, rd->r_sgname,
505 (void *)&sla);
506 /* we're trailing a ',' which we need to remove */
507 *--sla.buf = '\0';
509 return (B_TRUE);
512 #define RMAXCOLS 120 /* enough? */
513 #define SERVER_WIDTH (ILB_NAMESZ+1) /* 1st guess */
515 static boolean_t
516 of_port2str(in_port_t minport, in_port_t maxport, char *buf, uint_t bufsize)
518 in_port_t h_min, h_max;
519 int len;
521 h_min = ntohs(minport);
522 h_max = ntohs(maxport);
524 if (h_min == 0)
525 return (B_FALSE); /* print "unspec" == "all ports" */
527 len = snprintf(buf, bufsize, "%d", h_min);
528 if (h_max > h_min)
529 (void) snprintf(buf + len, bufsize - len, "-%d", h_max);
530 return (B_TRUE);
533 static ilbadm_status_t
534 ip2hostname(ilb_ip_addr_t *ip, char *buf, uint_t bufsize)
536 int ret;
537 struct hostent *he;
539 switch (ip->ia_af) {
540 case AF_INET:
541 he = getipnodebyaddr((char *)&ip->ia_v4, sizeof (ip->ia_v4),
542 ip->ia_af, &ret);
543 break;
544 case AF_INET6:
545 he = getipnodebyaddr((char *)&ip->ia_v6, sizeof (ip->ia_v6),
546 ip->ia_af, &ret);
547 break;
548 default: return (ILBADM_INVAL_AF);
551 /* if we can't resolve this, just return an empty name */
552 if (he == NULL)
553 buf[0] = '\0';
554 else
555 (void) strlcpy(buf, he->h_name, bufsize);
557 return (ILBADM_OK);
560 /* ARGSUSED */
562 * Since this function is used by libilb routine ilb_walk_rules()
563 * it must return libilb errors
565 static ilb_status_t
566 ilbadm_show_onerule(ilb_handle_t h, ilb_rule_data_t *rd, void *arg)
568 ilbadm_sh_rl_arg_t *larg = (ilbadm_sh_rl_arg_t *)arg;
569 ofmt_status_t oerr;
570 int oflags = 0;
571 int ocols = RMAXCOLS;
572 ilbadm_rl_list_arg_t ra;
573 static ofmt_handle_t oh = (ofmt_handle_t)NULL;
574 ofmt_field_t *fields;
575 boolean_t r_enabled = rd->r_flags & ILB_FLAGS_RULE_ENABLED;
577 if (larg->o_str == NULL) {
578 ilbadm_err(gettext("internal error"));
579 return (ILB_STATUS_GENERIC);
583 * only print rules (enabled/dis-) we're asked to
584 * note: both LIST_**ABLED flags can be set at the same time,
585 * whereas a rule has one state only. therefore the complicated
586 * statement.
588 if (!((r_enabled && (larg->flags & ILBADM_LIST_ENABLED)) ||
589 (!r_enabled && (larg->flags & ILBADM_LIST_DISABLED))))
590 return (ILB_STATUS_OK);
592 if (larg->flags & ILBADM_LIST_PARSE)
593 oflags |= OFMT_PARSABLE;
595 if (larg->flags & ILBADM_LIST_FULL)
596 oflags |= OFMT_MULTILINE;
598 bzero(&ra, sizeof (ra));
599 ra.rd = rd;
600 ra.h = h;
602 if (oh == NULL) {
603 if (rd->r_vip.ia_af == AF_INET)
604 fields = rfields_v4;
605 else
606 fields = rfields_v6;
608 oerr = ofmt_open(larg->o_str, fields, oflags, ocols, &oh);
609 if (oerr != OFMT_SUCCESS) {
610 char e[80];
612 ilbadm_err(gettext("ofmt_open failed: %s"),
613 ofmt_strerror(oh, oerr, e, sizeof (e)));
614 return (ILB_STATUS_GENERIC);
618 ofmt_print(oh, &ra);
620 return (ILB_STATUS_OK);
623 static char *full_list_rule_hdrs =
624 "RULENAME,STATUS,PORT,PROTOCOL,LBALG,TYPE,PROXY-SRC,PMASK,"
625 "HC-NAME,HC-PORT,CONN-DRAIN,NAT-TIMEOUT,"
626 "PERSIST-TIMEOUT,SERVERGROUP,VIP,SERVERS";
627 static char *def_list_rule_hdrs =
628 "RULENAME,STATUS,LBALG,TYPE,PROTOCOL,VIP,PORT";
630 /* ARGSUSED */
631 ilbadm_status_t
632 ilbadm_show_rules(int argc, char *argv[])
634 ilb_handle_t h = ILB_INVALID_HANDLE;
635 int c;
636 ilb_status_t rclib = ILB_STATUS_OK;
637 ilbadm_status_t rc = ILBADM_OK;
638 boolean_t o_opt = B_FALSE, p_opt = B_FALSE;
639 boolean_t f_opt = B_FALSE;
640 ilbadm_sh_rl_arg_t larg = {0, NULL, NULL, NULL};
642 larg.flags = ILBADM_LIST_ENABLED | ILBADM_LIST_DISABLED;
643 while ((c = getopt(argc, argv, ":fpedo:")) != -1) {
644 switch ((char)c) {
645 case 'f': larg.flags |= ILBADM_LIST_FULL;
646 larg.o_str = full_list_rule_hdrs;
647 f_opt = B_TRUE;
648 break;
649 case 'p': larg.flags |= ILBADM_LIST_PARSE;
650 p_opt = B_TRUE;
651 break;
652 case 'o': larg.o_str = optarg;
653 o_opt = B_TRUE;
654 break;
655 /* -e and -d may be repeated - make sure the last one wins */
656 case 'e': larg.flags &= ILBADM_LIST_NODISABLED;
657 larg.flags |= ILBADM_LIST_ENABLED;
658 break;
659 case 'd': larg.flags &= ILBADM_LIST_NOENABLED;
660 larg.flags |= ILBADM_LIST_DISABLED;
661 break;
662 case ':': ilbadm_err(gettext("missing option argument for %c"),
663 (char)optopt);
664 rc = ILBADM_LIBERR;
665 goto out;
666 case '?':
667 default:
668 unknown_opt(argv, optind-1);
669 /* not reached */
670 break;
674 if (f_opt && o_opt) {
675 ilbadm_err(gettext("options -o and -f are mutually"
676 " exclusive"));
677 exit(1);
680 if (p_opt && !o_opt) {
681 ilbadm_err(gettext("option -p requires -o"));
682 exit(1);
685 if (p_opt && larg.o_str != NULL &&
686 (strcasecmp(larg.o_str, "all") == 0)) {
687 ilbadm_err(gettext("option -p requires explicit field"
688 " names for -o"));
689 exit(1);
692 /* no -o option, so we use std. fields */
693 if (!o_opt && !f_opt)
694 larg.o_str = def_list_rule_hdrs;
696 rclib = ilb_open(&h);
697 if (rclib != ILB_STATUS_OK)
698 goto out;
700 if (optind >= argc) {
701 rclib = ilb_walk_rules(h, ilbadm_show_onerule, NULL,
702 (void*)&larg);
703 } else {
704 while (optind < argc) {
705 rclib = ilb_walk_rules(h, ilbadm_show_onerule,
706 argv[optind++], (void*)&larg);
707 if (rclib != ILB_STATUS_OK)
708 break;
711 out:
712 if (h != ILB_INVALID_HANDLE)
713 (void) ilb_close(h);
715 if (rclib != ILB_STATUS_OK) {
717 * The show function returns ILB_STATUS_GENERIC after printing
718 * out an error message. So we don't need to print it again.
720 if (rclib != ILB_STATUS_GENERIC)
721 ilbadm_err(ilb_errstr(rclib));
722 rc = ILBADM_LIBERR;
724 return (rc);
727 static boolean_t
728 of_srv2str(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
730 ilbadm_rl_srvlist_arg_t *larg =
731 (ilbadm_rl_srvlist_arg_t *)of_arg->ofmt_cbarg;
732 ilb_server_data_t *sd = larg->sd;
733 uint_t op = of_arg->ofmt_id;
734 boolean_t ret = B_TRUE;
735 ilbadm_status_t rc;
737 if (sd == NULL)
738 return (B_FALSE);
740 switch (op) {
741 case OF_SRV_ID:
742 (void) strlcpy(buf, sd->sd_srvID, bufsize);
743 break;
744 case OF_SRV_STATUS:
745 if (ILB_IS_SRV_ENABLED(sd->sd_flags))
746 buf[0] = 'E';
747 else
748 buf[0] = 'D';
749 buf[1] = '\0';
750 break;
751 case OF_SRV_RNAME:
752 (void) strlcpy(buf, larg->rd->r_name, bufsize);
753 break;
754 case OF_SRV_SGNAME:
755 (void) strlcpy(buf, larg->sgname, bufsize);
756 break;
757 case OF_SRV_HOSTNAME:
758 rc = ip2hostname(&sd->sd_addr, buf, bufsize);
759 if (rc != ILBADM_OK) {
760 buf[0] = '\0';
761 ret = B_FALSE;
763 break;
764 case OF_SRV_PORT:
765 ret = of_port2str(sd->sd_minport, sd->sd_maxport,
766 buf, bufsize);
767 break;
768 case OF_SRV_ADDR:
769 ip2str(&sd->sd_addr, buf, bufsize, V6_ADDRONLY);
770 break;
773 return (ret);
776 /* ARGSUSED */
777 static ilb_status_t
778 i_show_rl_srv(ilb_handle_t h, ilb_server_data_t *sd, const char *sgname,
779 void *arg)
781 ilbadm_rl_srvlist_arg_t *larg = (ilbadm_rl_srvlist_arg_t *)arg;
783 larg->sd = sd;
784 ofmt_print(larg->oh, larg);
785 return (ILB_STATUS_OK);
788 /* ARGSUSED */
790 * Since this function is used by libilb routine ilb_walk_rules()
791 * it must return libilb errors
793 ilb_status_t
794 ilbadm_show_rl_servers(ilb_handle_t h, ilb_rule_data_t *rd, void *arg)
796 ofmt_status_t oerr;
797 int oflags = 0;
798 int ocols = RMAXCOLS;
799 ofmt_field_t *fields;
800 static ofmt_handle_t oh = (ofmt_handle_t)NULL;
801 ilbadm_rl_srvlist_arg_t *larg = (ilbadm_rl_srvlist_arg_t *)arg;
804 * in full mode, we currently re-open ofmt() for every rule; we use
805 * a variable number of lines, as we print one for every server
806 * attached to a rule.
808 if (larg->o_str == NULL) {
809 ilbadm_err(gettext("internal error"));
810 return (ILB_STATUS_GENERIC);
813 if (larg->flags & ILBADM_LIST_PARSE)
814 oflags |= OFMT_PARSABLE;
816 if (rd->r_vip.ia_af == AF_INET)
817 fields = ssfields_v4;
818 else
819 fields = ssfields_v6;
821 if (oh == NULL) {
822 oerr = ofmt_open(larg->o_str, fields, oflags, ocols, &oh);
823 if (oerr != OFMT_SUCCESS) {
824 char e[80];
826 ilbadm_err(gettext("ofmt_open failed: %s"),
827 ofmt_strerror(oh, oerr, e, sizeof (e)));
828 return (ILB_STATUS_GENERIC);
830 larg->oh = oh;
833 larg->rd = rd;
834 larg->sgname = rd->r_sgname;
836 return (ilb_walk_servers(h, i_show_rl_srv, rd->r_sgname, (void *)larg));
839 static char *def_show_srv_hdrs =
840 "SERVERID,ADDRESS,PORT,RULENAME,STATUS,SERVERGROUP";
842 /* ARGSUSED */
843 ilbadm_status_t
844 ilbadm_show_server(int argc, char *argv[])
846 ilb_handle_t h = ILB_INVALID_HANDLE;
847 int c;
848 ilb_status_t rclib = ILB_STATUS_OK;
849 ilbadm_status_t rc = ILBADM_OK;
850 boolean_t o_opt = B_FALSE, p_opt = B_FALSE;
851 ilbadm_rl_srvlist_arg_t larg;
853 bzero(&larg, sizeof (larg));
854 while ((c = getopt(argc, argv, ":po:")) != -1) {
855 switch ((char)c) {
856 case 'p': larg.flags |= ILBADM_LIST_PARSE;
857 p_opt = B_TRUE;
858 break;
859 case 'o': larg.o_str = optarg;
860 o_opt = B_TRUE;
861 break;
862 case ':': ilbadm_err(gettext("missing option argument for %c"),
863 (char)optopt);
864 rc = ILBADM_LIBERR;
865 goto out;
866 case '?':
867 default:
868 unknown_opt(argv, optind-1);
869 /* not reached */
870 break;
874 if (p_opt && !o_opt) {
875 ilbadm_err(gettext("option -p requires -o"));
876 exit(1);
879 if (p_opt && larg.o_str != NULL &&
880 (strcasecmp(larg.o_str, "all") == 0)) {
881 ilbadm_err(gettext("option -p requires explicit"
882 " field names for -o"));
883 exit(1);
886 /* no -o option, so we use default fields */
887 if (!o_opt)
888 larg.o_str = def_show_srv_hdrs;
890 rclib = ilb_open(&h);
891 if (rclib != ILB_STATUS_OK)
892 goto out;
894 if (optind >= argc) {
895 rclib = ilb_walk_rules(h, ilbadm_show_rl_servers, NULL,
896 (void*)&larg);
897 } else {
898 while (optind < argc) {
899 rclib = ilb_walk_rules(h, ilbadm_show_rl_servers,
900 argv[optind++], (void*)&larg);
901 if (rclib != ILB_STATUS_OK)
902 break;
905 out:
906 if (h != ILB_INVALID_HANDLE)
907 (void) ilb_close(h);
909 if (rclib != ILB_STATUS_OK) {
911 * The show function returns ILB_STATUS_GENERIC after printing
912 * out an error message. So we don't need to print it again.
914 if (rclib != ILB_STATUS_GENERIC)
915 ilbadm_err(ilb_errstr(rclib));
916 rc = ILBADM_LIBERR;
918 return (rc);
921 static ilbadm_status_t
922 i_parse_rl_arg(char *arg, ilb_rule_data_t *rd, ilbadm_key_name_t *keylist)
924 ilbadm_status_t rc;
926 rc = i_parse_optstring(arg, (void *) rd, keylist,
927 OPT_PORTS, NULL);
928 return (rc);
931 static void
932 i_ilbadm_alloc_rule(ilb_rule_data_t **rdp)
934 ilb_rule_data_t *rd;
936 *rdp = rd = (ilb_rule_data_t *)calloc(sizeof (*rd), 1);
937 if (rd == NULL)
938 return;
939 rd->r_proto = IPPROTO_TCP;
942 static void
943 i_ilbadm_free_rule(ilb_rule_data_t *rd)
945 free(rd);
948 /* ARGSUSED */
949 ilbadm_status_t
950 ilbadm_destroy_rule(int argc, char *argv[])
952 ilb_handle_t h = ILB_INVALID_HANDLE;
953 ilbadm_status_t rc = ILBADM_OK;
954 ilb_status_t rclib = ILB_STATUS_OK;
955 boolean_t all_rules = B_FALSE;
956 int c, i;
958 while ((c = getopt(argc, argv, ":a")) != -1) {
959 switch ((char)c) {
960 case 'a':
961 all_rules = B_TRUE;
962 break;
963 case '?':
964 default:
965 unknown_opt(argv, optind-1);
966 /* not reached */
967 break;
971 if (optind >= argc && !all_rules) {
972 ilbadm_err(gettext("usage: delete-rule -a | name"));
973 return (ILBADM_LIBERR);
976 /* either "-a" or rulename, not both */
977 if (optind < argc && all_rules) {
978 rc = ILBADM_INVAL_ARGS;
979 goto out;
982 rclib = ilb_open(&h);
983 if (rclib != ILB_STATUS_OK)
984 goto out;
986 if (all_rules) {
987 rclib = ilb_destroy_rule(h, NULL);
988 goto out;
991 for (i = optind; i < argc && rclib == ILB_STATUS_OK; i++)
992 rclib = ilb_destroy_rule(h, argv[i]);
994 out:
995 if (h != ILB_INVALID_HANDLE)
996 (void) ilb_close(h);
998 /* This prints the specific errors */
999 if (rclib != ILB_STATUS_OK) {
1000 ilbadm_err(ilb_errstr(rclib));
1001 rc = ILBADM_LIBERR;
1003 /* This prints the generic errors */
1004 if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR))
1005 ilbadm_err(ilbadm_errstr(rc));
1006 return (rc);
1009 /* ARGSUSED */
1010 static ilbadm_status_t
1011 ilbadm_Xable_rule(int argc, char *argv[], ilbadm_cmd_t cmd)
1013 ilb_handle_t h = ILB_INVALID_HANDLE;
1014 ilb_status_t rclib = ILB_STATUS_OK;
1015 ilbadm_status_t rc = ILBADM_OK;
1016 int i;
1018 rclib = ilb_open(&h);
1019 if (rclib != ILB_STATUS_OK)
1020 goto out;
1022 * by default, en/disable-rule mean "all", and not using
1023 * a rule name will cause this behaviour to kick in
1025 if (argc < 2) {
1026 if (cmd == cmd_enable_rule)
1027 rclib = ilb_enable_rule(h, NULL);
1028 else
1029 rclib = ilb_disable_rule(h, NULL);
1030 } else {
1032 for (i = optind; i < argc && rc == ILBADM_OK; i++) {
1033 if (cmd == cmd_enable_rule)
1034 rclib = ilb_enable_rule(h, argv[i]);
1035 else
1036 rclib = ilb_disable_rule(h, argv[i]);
1039 out:
1040 if (h != ILB_INVALID_HANDLE)
1041 (void) ilb_close(h);
1043 if (rclib != ILB_STATUS_OK) {
1044 ilbadm_err(ilb_errstr(rclib));
1045 rc = ILBADM_LIBERR;
1047 return (rc);
1050 ilbadm_status_t
1051 ilbadm_enable_rule(int argc, char *argv[])
1054 return (ilbadm_Xable_rule(argc, argv, cmd_enable_rule));
1057 ilbadm_status_t
1058 ilbadm_disable_rule(int argc, char *argv[])
1060 return (ilbadm_Xable_rule(argc, argv, cmd_disable_rule));
1064 * parse and create a rule
1066 ilbadm_status_t
1067 ilbadm_create_rule(int argc, char *argv[])
1069 ilb_handle_t h = ILB_INVALID_HANDLE;
1070 int c;
1071 ilb_status_t rclib = ILB_STATUS_OK;
1072 ilbadm_status_t rc = ILBADM_OK;
1073 ilb_rule_data_t *rd;
1074 boolean_t p_opt = B_FALSE;
1076 i_ilbadm_alloc_rule(&rd);
1078 while ((c = getopt(argc, argv, ":ei:m:o:t:h:p")) != -1) {
1079 switch ((char)c) {
1080 case 'e':
1081 rd->r_flags |= ILB_FLAGS_RULE_ENABLED;
1082 break;
1083 case 'h':
1085 * Default value of of r_hcpflag means that if there
1086 * is a port range, probe any port. If there is only
1087 * one port, probe that port.
1089 rd->r_hcpflag = ILB_HCI_PROBE_ANY;
1090 rc = i_parse_rl_arg(optarg, rd, &rl_healthchk_keys[0]);
1091 break;
1092 case 'o':
1093 rc = i_parse_rl_arg(optarg, rd, &rl_outgoing_keys[0]);
1094 break;
1095 case 'm':
1096 rc = i_parse_rl_arg(optarg, rd, &rl_method_keys[0]);
1097 break;
1098 case 't':
1099 rc = i_parse_rl_arg(optarg, rd, &rl_timer_keys[0]);
1100 break;
1101 case 'i':
1102 rc = i_parse_rl_arg(optarg, rd, &rl_incoming_keys[0]);
1103 break;
1104 case 'p':
1105 p_opt = B_TRUE;
1106 break;
1107 case ':':
1108 ilbadm_err(gettext("missing option-argument"
1109 " for %c"), (char)optopt);
1110 rc = ILBADM_LIBERR;
1111 break;
1112 case '?':
1113 default:
1114 unknown_opt(argv, optind-1);
1115 /* not reached */
1116 break;
1119 if (rc != ILBADM_OK)
1120 goto out;
1123 if (optind >= argc) {
1124 ilbadm_err(gettext("missing mandatory arguments - please refer"
1125 " to 'ilbadm create-rule' subcommand description in"
1126 " ilbadm(1M)"));
1127 rc = ILBADM_LIBERR;
1128 goto out;
1132 if (p_opt) {
1134 * if user hasn't specified a mask, apply default
1136 if ((rd->r_flags & ILB_FLAGS_RULE_STICKY) == 0) {
1137 char *maskstr;
1139 switch (rd->r_vip.ia_af) {
1140 case AF_INET:
1141 maskstr = "32";
1142 break;
1143 case AF_INET6:
1144 maskstr = "128";
1145 break;
1147 rc = ilbadm_set_netmask(maskstr, &rd->r_stickymask,
1148 rd->r_vip.ia_af);
1149 if (rc != ILBADM_OK) {
1150 ilbadm_err(gettext("trouble seting default"
1151 " persistence mask"));
1152 rc = ILBADM_LIBERR;
1153 goto out;
1156 } else {
1157 /* use of sticky mask currently mandates "-p" */
1158 if ((rd->r_flags & ILB_FLAGS_RULE_STICKY) != 0) {
1159 ilbadm_err(gettext("use of stickymask requires"
1160 " -p option"));
1161 rc = ILBADM_LIBERR;
1162 goto out;
1166 if (strlen(argv[optind]) > ILBD_NAMESZ -1) {
1167 ilbadm_err(gettext("rule name %s is too long -"
1168 " must not exceed %d chars"), argv[optind],
1169 ILBD_NAMESZ - 1);
1170 rc = ILBADM_LIBERR;
1171 goto out;
1174 (void) strlcpy(rd->r_name, argv[optind], sizeof (rd->r_name));
1176 rc = i_check_rule_spec(rd);
1177 if (rc != ILBADM_OK)
1178 goto out;
1180 rclib = ilb_open(&h);
1181 if (rclib != ILB_STATUS_OK)
1182 goto out;
1184 rclib = ilb_create_rule(h, rd);
1186 out:
1187 i_ilbadm_free_rule(rd);
1189 if (h != ILB_INVALID_HANDLE)
1190 (void) ilb_close(h);
1192 if (rclib != ILB_STATUS_OK) {
1193 ilbadm_err(ilb_errstr(rclib));
1194 rc = ILBADM_LIBERR;
1196 if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR))
1197 ilbadm_err(ilbadm_errstr(rc));
1199 return (rc);
1202 /* ARGSUSED */
1205 * Since this function is used by libilb function, ilb_walk_rules()
1206 * it must return libilb errors
1208 static ilb_status_t
1209 ilbadm_export_rl(ilb_handle_t h, ilb_rule_data_t *rd, void *arg)
1211 char linebuf[128]; /* should be enough */
1212 int sz = sizeof (linebuf);
1213 FILE *fp = ((ilbadm_rl_exp_arg_t *)arg)->fp;
1214 uint32_t conndrain, nat_timeout, sticky_timeout;
1216 (void) fprintf(fp, "create-rule ");
1217 if (rd->r_flags & ILB_FLAGS_RULE_ENABLED)
1218 (void) fprintf(fp, "-e ");
1219 if (rd->r_flags & ILB_FLAGS_RULE_STICKY)
1220 (void) fprintf(fp, "-p ");
1222 ip2str(&rd->r_vip, linebuf, sz, V6_ADDRONLY);
1223 (void) fprintf(fp, "-i vip=%s,", linebuf);
1225 (void) ports2str(ntohs(rd->r_minport), ntohs(rd->r_maxport),
1226 linebuf, sz);
1227 (void) fprintf(fp, "%s,", linebuf);
1229 proto2str(rd->r_proto, linebuf, sz);
1230 (void) fprintf(fp, "%s ", linebuf);
1232 algo2str(rd->r_algo, linebuf, sz);
1233 (void) fprintf(fp, "-m %s,", linebuf);
1235 topo2str(rd->r_topo, linebuf, sz);
1236 (void) fprintf(fp, "%s", linebuf);
1238 if (rd->r_nat_src_start.ia_af != AF_UNSPEC) {
1239 ip2str(&rd->r_nat_src_start, linebuf, sz, V6_ADDRONLY);
1240 /* if the address is unspecified, skip it */
1241 if (linebuf[0] != '\0') {
1242 (void) fprintf(fp, ",proxy-src=%s", linebuf);
1243 ip2str(&rd->r_nat_src_end, linebuf, sz, V6_ADDRONLY);
1244 (void) fprintf(fp, "-%s", linebuf);
1248 if (rd->r_flags & ILB_FLAGS_RULE_STICKY) {
1249 (void) fprintf(fp, ",pmask=/%d",
1250 ilbadm_mask_to_prefixlen(&rd->r_stickymask));
1253 (void) fprintf(fp, " ");
1255 if (*rd->r_hcname != '\0') {
1256 (void) fprintf(fp, "-h hc-name=%s", rd->r_hcname);
1257 hcport_print(rd, linebuf, sizeof (linebuf));
1259 if (linebuf[0] != '\0')
1260 (void) fprintf(fp, ",hc-port=%s", linebuf);
1261 (void) fprintf(fp, " ");
1264 conndrain = rd->r_conndrain;
1265 nat_timeout = rd->r_nat_timeout;
1266 sticky_timeout = rd->r_sticky_timeout;
1267 if (conndrain != 0 || nat_timeout != 0 || sticky_timeout != 0) {
1268 int cnt = 0;
1270 (void) fprintf(fp, "-t ");
1271 if (conndrain != 0) {
1272 cnt++;
1273 (void) fprintf(fp, "conn-drain=%u", conndrain);
1275 if (nat_timeout != 0) {
1276 if (cnt > 0)
1277 (void) fprintf(fp, ",");
1278 cnt++;
1279 (void) fprintf(fp, "nat-timeout=%u", nat_timeout);
1281 if (sticky_timeout != 0) {
1282 if (cnt > 0)
1283 (void) fprintf(fp, ",");
1284 (void) fprintf(fp, "persist-timeout=%u",
1285 sticky_timeout);
1287 (void) fprintf(fp, " ");
1290 if (fprintf(fp, "-o servergroup=%s %s\n", rd->r_sgname, rd->r_name)
1291 < 0 || fflush(fp) == EOF)
1292 return (ILB_STATUS_WRITE);
1294 return (ILB_STATUS_OK);
1297 ilbadm_status_t
1298 ilbadm_export_rules(ilb_handle_t h, FILE *fp)
1300 ilb_status_t rclib;
1301 ilbadm_status_t rc = ILBADM_OK;
1302 ilbadm_rl_exp_arg_t arg;
1304 arg.fp = fp;
1306 rclib = ilb_walk_rules(h, ilbadm_export_rl, NULL, (void *)&arg);
1307 if (rclib != ILB_STATUS_OK)
1308 rc = ILBADM_LIBERR;
1309 return (rc);