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