1dbed73cbSSangeeta Misra /*
2dbed73cbSSangeeta Misra  * CDDL HEADER START
3dbed73cbSSangeeta Misra  *
4dbed73cbSSangeeta Misra  * The contents of this file are subject to the terms of the
5dbed73cbSSangeeta Misra  * Common Development and Distribution License (the "License").
6dbed73cbSSangeeta Misra  * You may not use this file except in compliance with the License.
7dbed73cbSSangeeta Misra  *
8dbed73cbSSangeeta Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dbed73cbSSangeeta Misra  * or http://www.opensolaris.org/os/licensing.
10dbed73cbSSangeeta Misra  * See the License for the specific language governing permissions
11dbed73cbSSangeeta Misra  * and limitations under the License.
12dbed73cbSSangeeta Misra  *
13dbed73cbSSangeeta Misra  * When distributing Covered Code, include this CDDL HEADER in each
14dbed73cbSSangeeta Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dbed73cbSSangeeta Misra  * If applicable, add the following below this CDDL HEADER, with the
16dbed73cbSSangeeta Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17dbed73cbSSangeeta Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18dbed73cbSSangeeta Misra  *
19dbed73cbSSangeeta Misra  * CDDL HEADER END
20dbed73cbSSangeeta Misra  */
21dbed73cbSSangeeta Misra 
22dbed73cbSSangeeta Misra /*
23dbed73cbSSangeeta Misra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24dbed73cbSSangeeta Misra  * Use is subject to license terms.
25*33f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
26dbed73cbSSangeeta Misra  */
27dbed73cbSSangeeta Misra 
28dbed73cbSSangeeta Misra #include <stdio.h>
29dbed73cbSSangeeta Misra #include <unistd.h>
30dbed73cbSSangeeta Misra #include <stdlib.h>
31dbed73cbSSangeeta Misra #include <strings.h>
32dbed73cbSSangeeta Misra #include <sys/types.h>
33dbed73cbSSangeeta Misra #include <sys/socket.h>
34dbed73cbSSangeeta Misra #include <sys/sysmacros.h>
35dbed73cbSSangeeta Misra #include <sys/note.h>
36dbed73cbSSangeeta Misra #include <fcntl.h>
37dbed73cbSSangeeta Misra #include <errno.h>
38dbed73cbSSangeeta Misra #include <assert.h>
39dbed73cbSSangeeta Misra #include <libgen.h>
40dbed73cbSSangeeta Misra #include <kstat.h>
41dbed73cbSSangeeta Misra #include <ofmt.h>
42dbed73cbSSangeeta Misra #include <libilb.h>
43dbed73cbSSangeeta Misra #include "ilbadm.h"
44dbed73cbSSangeeta Misra 
45dbed73cbSSangeeta Misra #define	ILBST_TIMESTAMP_HEADER	0x01	/* a timestamp w. every header */
46dbed73cbSSangeeta Misra #define	ILBST_DELTA_INTERVAL	0x02	/* delta over specified interval */
47dbed73cbSSangeeta Misra #define	ILBST_ABS_NUMBERS	0x04	/* print absolute numbers, no d's */
48dbed73cbSSangeeta Misra #define	ILBST_ITEMIZE		0x08	/* itemize */
49dbed73cbSSangeeta Misra #define	ILBST_VERBOSE		0x10	/* verbose error info */
50dbed73cbSSangeeta Misra 
51dbed73cbSSangeeta Misra #define	ILBST_OLD_VALUES	0x20	/* for internal processing */
52dbed73cbSSangeeta Misra #define	ILBST_RULES_CHANGED	0x40
53dbed73cbSSangeeta Misra 
54dbed73cbSSangeeta Misra typedef struct {
55dbed73cbSSangeeta Misra 	char		is_name[KSTAT_STRLEN];
56dbed73cbSSangeeta Misra 	uint64_t	is_value;
57dbed73cbSSangeeta Misra } ilbst_stat_t;
58dbed73cbSSangeeta Misra 
59dbed73cbSSangeeta Misra static ilbst_stat_t rulestats[] = {
60dbed73cbSSangeeta Misra 	{"num_servers", 0},
61dbed73cbSSangeeta Misra 	{"bytes_not_processed", 0},
62dbed73cbSSangeeta Misra 	{"pkt_not_processed", 0},
63dbed73cbSSangeeta Misra 	{"bytes_dropped", 0},
64dbed73cbSSangeeta Misra 	{"pkt_dropped", 0},
65dbed73cbSSangeeta Misra 	{"nomem_bytes_dropped", 0},
66dbed73cbSSangeeta Misra 	{"nomem_pkt_dropped", 0},
67dbed73cbSSangeeta Misra 	{"noport_bytes_dropped", 0},
68dbed73cbSSangeeta Misra 	{"noport_pkt_dropped", 0},
69dbed73cbSSangeeta Misra 	{"icmp_echo_processed", 0},
70dbed73cbSSangeeta Misra 	{"icmp_dropped", 0},
71dbed73cbSSangeeta Misra 	{"icmp_too_big_processed", 0},
72dbed73cbSSangeeta Misra 	{"icmp_too_big_dropped", 0}
73dbed73cbSSangeeta Misra };
74dbed73cbSSangeeta Misra 
75dbed73cbSSangeeta Misra /* indices into array above, to avoid searching */
76dbed73cbSSangeeta Misra #define	RLSTA_NUM_SRV		0
77dbed73cbSSangeeta Misra #define	RLSTA_BYTES_U		1
78dbed73cbSSangeeta Misra #define	RLSTA_PKT_U		2
79dbed73cbSSangeeta Misra #define	RLSTA_BYTES_D		3
80dbed73cbSSangeeta Misra #define	RLSTA_PKT_D		4
81dbed73cbSSangeeta Misra #define	RLSTA_NOMEMBYTES_D	5
82dbed73cbSSangeeta Misra #define	RLSTA_NOMEMPKT_D	6
83dbed73cbSSangeeta Misra #define	RLSTA_NOPORTBYTES_D	7
84dbed73cbSSangeeta Misra #define	RLSTA_NOPORTPKT_D	8
85dbed73cbSSangeeta Misra #define	RLSTA_ICMP_P		9
86dbed73cbSSangeeta Misra #define	RLSTA_ICMP_D		10
87dbed73cbSSangeeta Misra #define	RLSTA_ICMP2BIG_P	11
88dbed73cbSSangeeta Misra #define	RLSTA_ICMP2BIG_D	12
89dbed73cbSSangeeta Misra 
90dbed73cbSSangeeta Misra static ilbst_stat_t servstats[] = {
91dbed73cbSSangeeta Misra 	{"bytes_processed", 0},
92dbed73cbSSangeeta Misra 	{"pkt_processed", 0}
93dbed73cbSSangeeta Misra };
94dbed73cbSSangeeta Misra /* indices into array above, to avoid searching */
95dbed73cbSSangeeta Misra #define	SRVST_BYTES_P	0
96dbed73cbSSangeeta Misra #define	SRVST_PKT_P	1
97dbed73cbSSangeeta Misra 
98dbed73cbSSangeeta Misra /* values used for of_* commands as id */
99dbed73cbSSangeeta Misra #define	ILBST_PKT_P		0
100dbed73cbSSangeeta Misra #define	ILBST_BYTES_P		1
101dbed73cbSSangeeta Misra #define	ILBST_PKT_U		2
102dbed73cbSSangeeta Misra #define	ILBST_BYTES_U		3
103dbed73cbSSangeeta Misra #define	ILBST_PKT_D		4
104dbed73cbSSangeeta Misra #define	ILBST_BYTES_D		5
105dbed73cbSSangeeta Misra #define	ILBST_ICMP_P		6
106dbed73cbSSangeeta Misra #define	ILBST_ICMP_D		7
107dbed73cbSSangeeta Misra #define	ILBST_ICMP2BIG_P	8
108dbed73cbSSangeeta Misra #define	ILBST_ICMP2BIG_D	9
109dbed73cbSSangeeta Misra #define	ILBST_NOMEMP_D		10
110dbed73cbSSangeeta Misra #define	ILBST_NOPORTP_D		11
111dbed73cbSSangeeta Misra #define	ILBST_NOMEMB_D		12
112dbed73cbSSangeeta Misra #define	ILBST_NOPORTB_D		13
113dbed73cbSSangeeta Misra 
114dbed73cbSSangeeta Misra #define	ILBST_ITEMIZE_SNAME	97
115dbed73cbSSangeeta Misra #define	ILBST_ITEMIZE_RNAME	98
116dbed73cbSSangeeta Misra #define	ILBST_TIMESTAMP		99
117dbed73cbSSangeeta Misra 
118dbed73cbSSangeeta Misra /* approx field widths */
119dbed73cbSSangeeta Misra #define	ILBST_PKTCTR_W		8
120dbed73cbSSangeeta Misra #define	ILBST_BYTECTR_W		10
121dbed73cbSSangeeta Misra #define	ILBST_TIME_W		15
122dbed73cbSSangeeta Misra 
123dbed73cbSSangeeta Misra static boolean_t of_rule_stats(ofmt_arg_t *, char *, uint_t);
124dbed73cbSSangeeta Misra static boolean_t of_server_stats(ofmt_arg_t *, char *, uint_t);
125dbed73cbSSangeeta Misra static boolean_t of_itemize_stats(ofmt_arg_t *, char *, uint_t);
126dbed73cbSSangeeta Misra static boolean_t of_timestamp(ofmt_arg_t *, char *, uint_t);
127dbed73cbSSangeeta Misra 
128dbed73cbSSangeeta Misra static ofmt_field_t stat_itemize_fields[] = {
129dbed73cbSSangeeta Misra 	{"RULENAME", ILB_NAMESZ,	ILBST_ITEMIZE_RNAME, of_itemize_stats},
130dbed73cbSSangeeta Misra 	{"SERVERNAME", ILB_NAMESZ,	ILBST_ITEMIZE_SNAME, of_itemize_stats},
131dbed73cbSSangeeta Misra 	{"PKT_P",   ILBST_PKTCTR_W,	ILBST_PKT_P, of_itemize_stats},
132dbed73cbSSangeeta Misra 	{"BYTES_P", ILBST_BYTECTR_W,	ILBST_BYTES_P, of_itemize_stats},
133dbed73cbSSangeeta Misra 	{"TIME",    ILBST_TIME_W,	ILBST_TIMESTAMP, of_timestamp},
134dbed73cbSSangeeta Misra 	{NULL,	    0, 0, NULL}
135dbed73cbSSangeeta Misra };
136dbed73cbSSangeeta Misra static ofmt_field_t stat_stdfields[] = {
137dbed73cbSSangeeta Misra 	{"PKT_P",   ILBST_PKTCTR_W,	ILBST_PKT_P, of_server_stats},
138dbed73cbSSangeeta Misra 	{"BYTES_P", ILBST_BYTECTR_W,	ILBST_BYTES_P, of_server_stats},
139dbed73cbSSangeeta Misra 	{"PKT_U",   ILBST_PKTCTR_W,	ILBST_PKT_U, of_rule_stats},
140dbed73cbSSangeeta Misra 	{"BYTES_U", ILBST_BYTECTR_W,	ILBST_BYTES_U, of_rule_stats},
141dbed73cbSSangeeta Misra 	{"PKT_D",   ILBST_PKTCTR_W,	ILBST_PKT_D, of_rule_stats},
142dbed73cbSSangeeta Misra 	{"BYTES_D", ILBST_BYTECTR_W,	ILBST_BYTES_D, of_rule_stats},
143dbed73cbSSangeeta Misra 	{"ICMP_P",  ILBST_PKTCTR_W,	ILBST_ICMP_P, of_rule_stats},
144dbed73cbSSangeeta Misra 	{"ICMP_D",  ILBST_PKTCTR_W,	ILBST_ICMP_D, of_rule_stats},
145dbed73cbSSangeeta Misra 	{"ICMP2BIG_P", 11,		ILBST_ICMP2BIG_P, of_rule_stats},
146dbed73cbSSangeeta Misra 	{"ICMP2BIG_D", 11,		ILBST_ICMP2BIG_D, of_rule_stats},
147dbed73cbSSangeeta Misra 	{"NOMEMP_D", ILBST_PKTCTR_W,	ILBST_NOMEMP_D, of_rule_stats},
148dbed73cbSSangeeta Misra 	{"NOPORTP_D", ILBST_PKTCTR_W,	ILBST_NOPORTP_D, of_rule_stats},
149dbed73cbSSangeeta Misra 	{"NOMEMB_D", ILBST_PKTCTR_W,	ILBST_NOMEMB_D, of_rule_stats},
150dbed73cbSSangeeta Misra 	{"NOPORTB_D", ILBST_PKTCTR_W,	ILBST_NOPORTB_D, of_rule_stats},
151dbed73cbSSangeeta Misra 	{"TIME",    ILBST_TIME_W,	ILBST_TIMESTAMP, of_timestamp},
152dbed73cbSSangeeta Misra 	{NULL,	    0, 0, NULL}
153dbed73cbSSangeeta Misra };
154dbed73cbSSangeeta Misra 
155dbed73cbSSangeeta Misra static char stat_stdhdrs[] = "PKT_P,BYTES_P,PKT_U,BYTES_U,PKT_D,BYTES_D";
156dbed73cbSSangeeta Misra static char stat_stdv_hdrs[] = "PKT_P,BYTES_P,PKT_U,BYTES_U,PKT_D,BYTES_D,"
157dbed73cbSSangeeta Misra 	"ICMP_P,ICMP_D,ICMP2BIG_P,ICMP2BIG_D,NOMEMP_D,NOPORTP_D";
158dbed73cbSSangeeta Misra static char stat_itemize_rule_hdrs[] = "SERVERNAME,PKT_P,BYTES_P";
159dbed73cbSSangeeta Misra static char stat_itemize_server_hdrs[] = "RULENAME,PKT_P,BYTES_P";
160dbed73cbSSangeeta Misra 
161dbed73cbSSangeeta Misra #define	RSTAT_SZ	(sizeof (rulestats)/sizeof (rulestats[0]))
162dbed73cbSSangeeta Misra #define	SSTAT_SZ	(sizeof (servstats)/sizeof (servstats[0]))
163dbed73cbSSangeeta Misra 
164dbed73cbSSangeeta Misra typedef struct {
165dbed73cbSSangeeta Misra 	char		isd_servername[KSTAT_STRLEN]; /* serverID */
166dbed73cbSSangeeta Misra 	ilbst_stat_t	isd_serverstats[SSTAT_SZ];
167dbed73cbSSangeeta Misra 	hrtime_t	isd_crtime;	/* save for comparison purpose */
168dbed73cbSSangeeta Misra } ilbst_srv_desc_t;
169dbed73cbSSangeeta Misra 
170dbed73cbSSangeeta Misra /*
171dbed73cbSSangeeta Misra  * this data structure stores statistics for a rule - both an old set
172dbed73cbSSangeeta Misra  * and a current/new set. we use pointers to the actual stores and switch
173dbed73cbSSangeeta Misra  * the pointers for every round. old_is_old in ilbst_arg_t indicates
174dbed73cbSSangeeta Misra  * which pointer points to the "old" data struct (ie, if true, _o pointer
175dbed73cbSSangeeta Misra  * points to old)
176dbed73cbSSangeeta Misra  */
177dbed73cbSSangeeta Misra typedef struct {
178dbed73cbSSangeeta Misra 	char			ird_rulename[KSTAT_STRLEN];
179dbed73cbSSangeeta Misra 	int			ird_num_servers;
180dbed73cbSSangeeta Misra 	int			ird_num_servers_o;
181dbed73cbSSangeeta Misra 	int			ird_srv_ind;
182dbed73cbSSangeeta Misra 	hrtime_t		ird_crtime;	/* save for comparison */
183dbed73cbSSangeeta Misra 	hrtime_t		ird_crtime_o;	/* save for comparison */
184dbed73cbSSangeeta Misra 	ilbst_srv_desc_t	*ird_srvlist;
185dbed73cbSSangeeta Misra 	ilbst_srv_desc_t	*ird_srvlist_o;
186dbed73cbSSangeeta Misra 	ilbst_stat_t		ird_rstats[RSTAT_SZ];
187dbed73cbSSangeeta Misra 	ilbst_stat_t		ird_rstats_o[RSTAT_SZ];
188dbed73cbSSangeeta Misra 	ilbst_stat_t		*ird_rulestats;
189dbed73cbSSangeeta Misra 	ilbst_stat_t		*ird_rulestats_o;
190dbed73cbSSangeeta Misra } ilbst_rule_desc_t;
191dbed73cbSSangeeta Misra 
192dbed73cbSSangeeta Misra /*
193dbed73cbSSangeeta Misra  * overall "container" for information pertaining to statistics, and
194dbed73cbSSangeeta Misra  * how to display them.
195dbed73cbSSangeeta Misra  */
196dbed73cbSSangeeta Misra typedef struct {
197dbed73cbSSangeeta Misra 	int			ilbst_flags;
198dbed73cbSSangeeta Misra 	/* fields representing user input */
199dbed73cbSSangeeta Misra 	char			*ilbst_rulename;	/* optional */
200dbed73cbSSangeeta Misra 	char 			*ilbst_server;	/* optional */
201dbed73cbSSangeeta Misra 	int			ilbst_interval;
202dbed73cbSSangeeta Misra 	int			ilbst_count;
203dbed73cbSSangeeta Misra 	/* "internal" fields for data and data presentation */
204dbed73cbSSangeeta Misra 	ofmt_handle_t		ilbst_oh;
205dbed73cbSSangeeta Misra 	boolean_t		ilbst_old_is_old;
206dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*ilbst_rlist;
207dbed73cbSSangeeta Misra 	int			ilbst_rcount;	  /* current list count */
208dbed73cbSSangeeta Misra 	int			ilbst_rcount_prev; /* prev (different) count */
209dbed73cbSSangeeta Misra 	int			ilbst_rlist_sz; /* number of alloc'ed rules */
210dbed73cbSSangeeta Misra 	int			ilbst_rule_index; /* for itemizes display */
211dbed73cbSSangeeta Misra } ilbst_arg_t;
212dbed73cbSSangeeta Misra 
213dbed73cbSSangeeta Misra /* ARGSUSED */
214dbed73cbSSangeeta Misra static boolean_t
of_timestamp(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)215dbed73cbSSangeeta Misra of_timestamp(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
216dbed73cbSSangeeta Misra {
217dbed73cbSSangeeta Misra 	time_t		now;
218dbed73cbSSangeeta Misra 	struct tm	*now_tm;
219dbed73cbSSangeeta Misra 
220dbed73cbSSangeeta Misra 	now = time(NULL);
221dbed73cbSSangeeta Misra 	now_tm = localtime(&now);
222dbed73cbSSangeeta Misra 
223dbed73cbSSangeeta Misra 	(void) strftime(buf, bufsize, "%F:%H.%M.%S", now_tm);
224dbed73cbSSangeeta Misra 	return (B_TRUE);
225dbed73cbSSangeeta Misra }
226dbed73cbSSangeeta Misra 
227dbed73cbSSangeeta Misra static boolean_t
i_sum_per_rule_processed(ilbst_rule_desc_t * rp,uint64_t * resp,int index,int flags)228dbed73cbSSangeeta Misra i_sum_per_rule_processed(ilbst_rule_desc_t *rp, uint64_t *resp, int index,
229dbed73cbSSangeeta Misra     int flags)
230dbed73cbSSangeeta Misra {
231dbed73cbSSangeeta Misra 	int			i, num_servers;
232dbed73cbSSangeeta Misra 	ilbst_srv_desc_t	*srv, *o_srv, *n_srv;
233dbed73cbSSangeeta Misra 	uint64_t		res = 0;
234dbed73cbSSangeeta Misra 	boolean_t		valid = B_TRUE;
235dbed73cbSSangeeta Misra 	boolean_t		old = flags & ILBST_OLD_VALUES;
236dbed73cbSSangeeta Misra 	boolean_t		check_valid;
237dbed73cbSSangeeta Misra 
238dbed73cbSSangeeta Misra 	/* if we do abs. numbers, we never look at the _o fields */
239dbed73cbSSangeeta Misra 	assert((old && (flags & ILBST_ABS_NUMBERS)) == B_FALSE);
240dbed73cbSSangeeta Misra 
241dbed73cbSSangeeta Misra 	/* we only check for validity under certain conditions */
242dbed73cbSSangeeta Misra 	check_valid = !(old || (flags & ILBST_ABS_NUMBERS));
243dbed73cbSSangeeta Misra 
244dbed73cbSSangeeta Misra 	if (check_valid && rp->ird_num_servers != rp->ird_num_servers_o)
245dbed73cbSSangeeta Misra 		valid = B_FALSE;
246dbed73cbSSangeeta Misra 
247dbed73cbSSangeeta Misra 	num_servers = old ? rp->ird_num_servers_o : rp->ird_num_servers;
248dbed73cbSSangeeta Misra 
249dbed73cbSSangeeta Misra 	for (i = 0; i < num_servers; i++) {
250dbed73cbSSangeeta Misra 		n_srv = &rp->ird_srvlist[i];
251dbed73cbSSangeeta Misra 		o_srv = &rp->ird_srvlist_o[i];
252dbed73cbSSangeeta Misra 
253dbed73cbSSangeeta Misra 		if (old)
254dbed73cbSSangeeta Misra 			srv = o_srv;
255dbed73cbSSangeeta Misra 		else
256dbed73cbSSangeeta Misra 			srv = n_srv;
257dbed73cbSSangeeta Misra 
258dbed73cbSSangeeta Misra 		res += srv->isd_serverstats[index].is_value;
259dbed73cbSSangeeta Misra 		/*
260dbed73cbSSangeeta Misra 		 * if creation times don't match, comparison is wrong; if
261dbed73cbSSangeeta Misra 		 * if we already know something is invalid, we don't
262dbed73cbSSangeeta Misra 		 * need to compare again.
263dbed73cbSSangeeta Misra 		 */
264dbed73cbSSangeeta Misra 		if (check_valid && valid == B_TRUE &&
265dbed73cbSSangeeta Misra 		    o_srv->isd_crtime != n_srv->isd_crtime) {
266dbed73cbSSangeeta Misra 			valid = B_FALSE;
267dbed73cbSSangeeta Misra 			break;
268dbed73cbSSangeeta Misra 		}
269dbed73cbSSangeeta Misra 	}
270dbed73cbSSangeeta Misra 	/*
271dbed73cbSSangeeta Misra 	 * save the result even though it may be imprecise  - let the
272dbed73cbSSangeeta Misra 	 * caller decide what to do
273dbed73cbSSangeeta Misra 	 */
274dbed73cbSSangeeta Misra 	*resp = res;
275dbed73cbSSangeeta Misra 
276dbed73cbSSangeeta Misra 	return (valid);
277dbed73cbSSangeeta Misra }
278dbed73cbSSangeeta Misra 
279dbed73cbSSangeeta Misra typedef boolean_t (*sumfunc_t)(ilbst_rule_desc_t *, uint64_t *, int);
280dbed73cbSSangeeta Misra 
281dbed73cbSSangeeta Misra static boolean_t
i_sum_per_rule_pkt_p(ilbst_rule_desc_t * rp,uint64_t * resp,int flags)282dbed73cbSSangeeta Misra i_sum_per_rule_pkt_p(ilbst_rule_desc_t *rp, uint64_t *resp, int flags)
283dbed73cbSSangeeta Misra {
284dbed73cbSSangeeta Misra 	return (i_sum_per_rule_processed(rp, resp, SRVST_PKT_P, flags));
285dbed73cbSSangeeta Misra }
286dbed73cbSSangeeta Misra 
287dbed73cbSSangeeta Misra static boolean_t
i_sum_per_rule_bytes_p(ilbst_rule_desc_t * rp,uint64_t * resp,int flags)288dbed73cbSSangeeta Misra i_sum_per_rule_bytes_p(ilbst_rule_desc_t *rp, uint64_t *resp, int flags)
289dbed73cbSSangeeta Misra {
290dbed73cbSSangeeta Misra 	return (i_sum_per_rule_processed(rp, resp, SRVST_BYTES_P, flags));
291dbed73cbSSangeeta Misra }
292dbed73cbSSangeeta Misra 
293dbed73cbSSangeeta Misra static boolean_t
of_server_stats(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)294dbed73cbSSangeeta Misra of_server_stats(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
295dbed73cbSSangeeta Misra {
296dbed73cbSSangeeta Misra 	ilbst_arg_t	*sta = (ilbst_arg_t *)of_arg->ofmt_cbarg;
297dbed73cbSSangeeta Misra 	uint64_t	count = 0, val;
298dbed73cbSSangeeta Misra 	int		i;
299dbed73cbSSangeeta Misra 	boolean_t	valid = B_TRUE;
300dbed73cbSSangeeta Misra 	sumfunc_t	sumfunc;
301dbed73cbSSangeeta Misra 
302dbed73cbSSangeeta Misra 	switch (of_arg->ofmt_id) {
303dbed73cbSSangeeta Misra 	case ILBST_PKT_P: sumfunc = i_sum_per_rule_pkt_p;
304dbed73cbSSangeeta Misra 		break;
305dbed73cbSSangeeta Misra 	case ILBST_BYTES_P: sumfunc = i_sum_per_rule_bytes_p;
306dbed73cbSSangeeta Misra 		break;
307dbed73cbSSangeeta Misra 	}
308dbed73cbSSangeeta Misra 
309dbed73cbSSangeeta Misra 	for (i = 0; i < sta->ilbst_rcount; i++) {
310dbed73cbSSangeeta Misra 		valid = sumfunc(&sta->ilbst_rlist[i], &val, sta->ilbst_flags);
311dbed73cbSSangeeta Misra 		if (!valid)
312dbed73cbSSangeeta Misra 			return (valid);
313dbed73cbSSangeeta Misra 		count += val;
314dbed73cbSSangeeta Misra 	}
315dbed73cbSSangeeta Misra 
316dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) != 0)
317dbed73cbSSangeeta Misra 		goto out;
318dbed73cbSSangeeta Misra 
319dbed73cbSSangeeta Misra 	for (i = 0; i < sta->ilbst_rcount; i++) {
320dbed73cbSSangeeta Misra 		(void) sumfunc(&sta->ilbst_rlist[i], &val,
321dbed73cbSSangeeta Misra 		    sta->ilbst_flags | ILBST_OLD_VALUES);
322dbed73cbSSangeeta Misra 		count -= val;
323dbed73cbSSangeeta Misra 	}
324dbed73cbSSangeeta Misra 
325dbed73cbSSangeeta Misra out:
326dbed73cbSSangeeta Misra 	/*
327dbed73cbSSangeeta Misra 	 * normally, we print "change per second", which we calculate
328dbed73cbSSangeeta Misra 	 * here. otherwise, we print "change over interval"
329dbed73cbSSangeeta Misra 	 */
330dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & (ILBST_DELTA_INTERVAL|ILBST_ABS_NUMBERS)) == 0)
331dbed73cbSSangeeta Misra 		count /= sta->ilbst_interval;
332dbed73cbSSangeeta Misra 
333dbed73cbSSangeeta Misra 	(void) snprintf(buf, bufsize, "%llu", count);
334dbed73cbSSangeeta Misra 	return (B_TRUE);
335dbed73cbSSangeeta Misra }
336dbed73cbSSangeeta Misra 
337dbed73cbSSangeeta Misra /*
338dbed73cbSSangeeta Misra  * this function is called when user wants itemized stats of every
339dbed73cbSSangeeta Misra  * server for a named rule, or vice vera.
340dbed73cbSSangeeta Misra  * i_do_print sets sta->rule_index and the proper ird_srv_ind so
341dbed73cbSSangeeta Misra  * we don't have to differentiate between these two cases here.
342dbed73cbSSangeeta Misra  */
343dbed73cbSSangeeta Misra static boolean_t
of_itemize_stats(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)344dbed73cbSSangeeta Misra of_itemize_stats(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
345dbed73cbSSangeeta Misra {
346dbed73cbSSangeeta Misra 	ilbst_arg_t	*sta = (ilbst_arg_t *)of_arg->ofmt_cbarg;
347dbed73cbSSangeeta Misra 	int		stat_ind;
348dbed73cbSSangeeta Misra 	uint64_t	count;
349dbed73cbSSangeeta Misra 	int		rule_index = sta->ilbst_rule_index;
350dbed73cbSSangeeta Misra 	int		srv_ind = sta->ilbst_rlist[rule_index].ird_srv_ind;
351dbed73cbSSangeeta Misra 	boolean_t	ret = B_TRUE;
352dbed73cbSSangeeta Misra 	ilbst_srv_desc_t *srv, *osrv;
353dbed73cbSSangeeta Misra 
354dbed73cbSSangeeta Misra 	srv = &sta->ilbst_rlist[rule_index].ird_srvlist[srv_ind];
355dbed73cbSSangeeta Misra 
356dbed73cbSSangeeta Misra 	switch (of_arg->ofmt_id) {
357dbed73cbSSangeeta Misra 	case ILBST_PKT_P: stat_ind = SRVST_PKT_P;
358dbed73cbSSangeeta Misra 		break;
359dbed73cbSSangeeta Misra 	case ILBST_BYTES_P: stat_ind = SRVST_BYTES_P;
360dbed73cbSSangeeta Misra 		break;
361dbed73cbSSangeeta Misra 	case ILBST_ITEMIZE_RNAME:
362dbed73cbSSangeeta Misra 		(void) snprintf(buf, bufsize, "%s",
363dbed73cbSSangeeta Misra 		    sta->ilbst_rlist[rule_index].ird_rulename);
364dbed73cbSSangeeta Misra 		return (B_TRUE);
365dbed73cbSSangeeta Misra 	case ILBST_ITEMIZE_SNAME:
366dbed73cbSSangeeta Misra 		(void) snprintf(buf, bufsize, "%s", srv->isd_servername);
367dbed73cbSSangeeta Misra 		return (B_TRUE);
368dbed73cbSSangeeta Misra 	}
369dbed73cbSSangeeta Misra 
370dbed73cbSSangeeta Misra 	count = srv->isd_serverstats[stat_ind].is_value;
371dbed73cbSSangeeta Misra 
372dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) != 0)
373dbed73cbSSangeeta Misra 		goto out;
374dbed73cbSSangeeta Misra 
375dbed73cbSSangeeta Misra 	osrv = &sta->ilbst_rlist[rule_index].ird_srvlist_o[srv_ind];
376dbed73cbSSangeeta Misra 	if (srv->isd_crtime != osrv->isd_crtime)
377dbed73cbSSangeeta Misra 		ret = B_FALSE;
378dbed73cbSSangeeta Misra 
379dbed73cbSSangeeta Misra 	count -= osrv->isd_serverstats[stat_ind].is_value;
380dbed73cbSSangeeta Misra out:
381dbed73cbSSangeeta Misra 	/*
382dbed73cbSSangeeta Misra 	 * normally, we print "change per second", which we calculate
383dbed73cbSSangeeta Misra 	 * here. otherwise, we print "change over interval" or absolute
384dbed73cbSSangeeta Misra 	 * values.
385dbed73cbSSangeeta Misra 	 */
386dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & (ILBST_DELTA_INTERVAL|ILBST_ABS_NUMBERS)) == 0)
387dbed73cbSSangeeta Misra 		count /= sta->ilbst_interval;
388dbed73cbSSangeeta Misra 
389dbed73cbSSangeeta Misra 	(void) snprintf(buf, bufsize, "%llu", count);
390dbed73cbSSangeeta Misra 	return (ret);
391dbed73cbSSangeeta Misra 
392dbed73cbSSangeeta Misra }
393dbed73cbSSangeeta Misra 
394dbed73cbSSangeeta Misra static boolean_t
of_rule_stats(ofmt_arg_t * of_arg,char * buf,uint_t bufsize)395dbed73cbSSangeeta Misra of_rule_stats(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
396dbed73cbSSangeeta Misra {
397dbed73cbSSangeeta Misra 	ilbst_arg_t	*sta = (ilbst_arg_t *)of_arg->ofmt_cbarg;
398dbed73cbSSangeeta Misra 	int		i, ind;
399dbed73cbSSangeeta Misra 	uint64_t	count = 0;
400dbed73cbSSangeeta Misra 
401dbed73cbSSangeeta Misra 	switch (of_arg->ofmt_id) {
402dbed73cbSSangeeta Misra 	case ILBST_PKT_U: ind = RLSTA_PKT_U;
403dbed73cbSSangeeta Misra 		break;
404dbed73cbSSangeeta Misra 	case ILBST_BYTES_U: ind = RLSTA_BYTES_U;
405dbed73cbSSangeeta Misra 		break;
406dbed73cbSSangeeta Misra 	case ILBST_PKT_D: ind = RLSTA_PKT_D;
407dbed73cbSSangeeta Misra 		break;
408dbed73cbSSangeeta Misra 	case ILBST_BYTES_D: ind = RLSTA_BYTES_D;
409dbed73cbSSangeeta Misra 		break;
410dbed73cbSSangeeta Misra 	case ILBST_ICMP_P: ind = RLSTA_ICMP_P;
411dbed73cbSSangeeta Misra 		break;
412dbed73cbSSangeeta Misra 	case ILBST_ICMP_D: ind = RLSTA_ICMP_D;
413dbed73cbSSangeeta Misra 		break;
414dbed73cbSSangeeta Misra 	case ILBST_ICMP2BIG_P: ind = RLSTA_ICMP2BIG_P;
415dbed73cbSSangeeta Misra 		break;
416dbed73cbSSangeeta Misra 	case ILBST_ICMP2BIG_D: ind = RLSTA_ICMP2BIG_D;
417dbed73cbSSangeeta Misra 		break;
418dbed73cbSSangeeta Misra 	case ILBST_NOMEMP_D: ind  = RLSTA_NOMEMPKT_D;
419dbed73cbSSangeeta Misra 		break;
420dbed73cbSSangeeta Misra 	case ILBST_NOPORTP_D: ind = RLSTA_NOPORTPKT_D;
421dbed73cbSSangeeta Misra 		break;
422dbed73cbSSangeeta Misra 	case ILBST_NOMEMB_D: ind = RLSTA_NOMEMBYTES_D;
423dbed73cbSSangeeta Misra 		break;
424dbed73cbSSangeeta Misra 	case ILBST_NOPORTB_D: ind = RLSTA_NOPORTBYTES_D;
425dbed73cbSSangeeta Misra 		break;
426dbed73cbSSangeeta Misra 	}
427dbed73cbSSangeeta Misra 
428dbed73cbSSangeeta Misra 	for (i = 0; i < sta->ilbst_rcount; i++)
429dbed73cbSSangeeta Misra 		count += sta->ilbst_rlist[i].ird_rulestats[ind].is_value;
430dbed73cbSSangeeta Misra 
431dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) != 0)
432dbed73cbSSangeeta Misra 		goto out;
433dbed73cbSSangeeta Misra 
434dbed73cbSSangeeta Misra 	/*
435dbed73cbSSangeeta Misra 	 * the purist approach: if we can't say 100% that what we
436dbed73cbSSangeeta Misra 	 * calculate is correct, don't.
437dbed73cbSSangeeta Misra 	 */
438dbed73cbSSangeeta Misra 	if (sta->ilbst_flags & ILBST_RULES_CHANGED)
439dbed73cbSSangeeta Misra 		return (B_FALSE);
440dbed73cbSSangeeta Misra 
441dbed73cbSSangeeta Misra 	for (i = 0; i < sta->ilbst_rcount; i++) {
442dbed73cbSSangeeta Misra 		if (sta->ilbst_rlist[i].ird_crtime_o != 0 &&
443dbed73cbSSangeeta Misra 		    sta->ilbst_rlist[i].ird_crtime !=
444dbed73cbSSangeeta Misra 		    sta->ilbst_rlist[i].ird_crtime_o)
445dbed73cbSSangeeta Misra 			return (B_FALSE);
446dbed73cbSSangeeta Misra 
447dbed73cbSSangeeta Misra 		count -= sta->ilbst_rlist[i].ird_rulestats_o[ind].is_value;
448dbed73cbSSangeeta Misra 	}
449dbed73cbSSangeeta Misra out:
450dbed73cbSSangeeta Misra 	/*
451dbed73cbSSangeeta Misra 	 * normally, we print "change per second", which we calculate
452dbed73cbSSangeeta Misra 	 * here. otherwise, we print "change over interval"
453dbed73cbSSangeeta Misra 	 */
454dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & (ILBST_DELTA_INTERVAL|ILBST_ABS_NUMBERS)) == 0)
455dbed73cbSSangeeta Misra 		count /= sta->ilbst_interval;
456dbed73cbSSangeeta Misra 
457dbed73cbSSangeeta Misra 	(void) snprintf(buf, bufsize, "%llu", count);
458dbed73cbSSangeeta Misra 	return (B_TRUE);
459dbed73cbSSangeeta Misra }
460dbed73cbSSangeeta Misra 
461dbed73cbSSangeeta Misra /*
462dbed73cbSSangeeta Misra  * Get the number of kstat instances. Note that when rules are being
463dbed73cbSSangeeta Misra  * drained the number of kstats instances may be different than the
464dbed73cbSSangeeta Misra  * kstat counter num_rules (ilb:0:global:num_rules").
465dbed73cbSSangeeta Misra  *
466dbed73cbSSangeeta Misra  * Also there can be multiple instances of a rule in the following
467dbed73cbSSangeeta Misra  * scenario:
468dbed73cbSSangeeta Misra  *
469dbed73cbSSangeeta Misra  * A rule named rule A has been deleted but remains in kstats because
470dbed73cbSSangeeta Misra  * its undergoing connection draining. During this time, the user adds
471dbed73cbSSangeeta Misra  * a new rule with the same name(rule A). In this case, there would
472dbed73cbSSangeeta Misra  * be two kstats instances for rule A. Currently ilbadm's aggregate
473dbed73cbSSangeeta Misra  * results will include data from both instances of rule A. In,
474dbed73cbSSangeeta Misra  * future we should have ilbadm stats only consider the latest instance
475dbed73cbSSangeeta Misra  * of the rule (ie only consider the the instance that corresponds
476dbed73cbSSangeeta Misra  * to the rule that was just added).
477dbed73cbSSangeeta Misra  *
478dbed73cbSSangeeta Misra  */
479dbed73cbSSangeeta Misra static int
i_get_num_kinstances(kstat_ctl_t * kctl)480dbed73cbSSangeeta Misra i_get_num_kinstances(kstat_ctl_t *kctl)
481dbed73cbSSangeeta Misra {
482dbed73cbSSangeeta Misra 	kstat_t		*kp;
483dbed73cbSSangeeta Misra 	int		num_instances = 0; /* nothing found, 0 rules */
484dbed73cbSSangeeta Misra 
485dbed73cbSSangeeta Misra 	for (kp = kctl->kc_chain; kp != NULL; kp = kp->ks_next) {
486dbed73cbSSangeeta Misra 		if (strncmp("rulestat", kp->ks_class, 8) == 0 &&
487dbed73cbSSangeeta Misra 		    strncmp("ilb", kp->ks_module, 3) == 0) {
488dbed73cbSSangeeta Misra 			num_instances++;
489dbed73cbSSangeeta Misra 		}
490dbed73cbSSangeeta Misra 	}
491dbed73cbSSangeeta Misra 
492dbed73cbSSangeeta Misra 	return (num_instances);
493dbed73cbSSangeeta Misra }
494dbed73cbSSangeeta Misra 
495dbed73cbSSangeeta Misra 
496dbed73cbSSangeeta Misra /*
497dbed73cbSSangeeta Misra  * since server stat's classname is made up of <rulename>-sstat,
498dbed73cbSSangeeta Misra  * we walk the rule list to construct the comparison
499dbed73cbSSangeeta Misra  * Return:	pointer to rule whose name matches the class
500dbed73cbSSangeeta Misra  *		NULL if no match
501dbed73cbSSangeeta Misra  */
502dbed73cbSSangeeta Misra static ilbst_rule_desc_t *
match_2_rnames(char * class,ilbst_rule_desc_t * rlist,int rcount)503dbed73cbSSangeeta Misra match_2_rnames(char *class, ilbst_rule_desc_t *rlist, int rcount)
504dbed73cbSSangeeta Misra {
505dbed73cbSSangeeta Misra 	int i;
506dbed73cbSSangeeta Misra 	char	classname[KSTAT_STRLEN];
507dbed73cbSSangeeta Misra 
508dbed73cbSSangeeta Misra 	for (i = 0; i < rcount; i++) {
509dbed73cbSSangeeta Misra 		(void) snprintf(classname, sizeof (classname), "%s-sstat",
510dbed73cbSSangeeta Misra 		    rlist[i].ird_rulename);
511dbed73cbSSangeeta Misra 		if (strncmp(classname, class, sizeof (classname)) == 0)
512dbed73cbSSangeeta Misra 			return (&rlist[i]);
513dbed73cbSSangeeta Misra 	}
514dbed73cbSSangeeta Misra 	return (NULL);
515dbed73cbSSangeeta Misra }
516dbed73cbSSangeeta Misra 
517dbed73cbSSangeeta Misra static int
i_stat_index(kstat_named_t * knp,ilbst_stat_t * stats,int count)518dbed73cbSSangeeta Misra i_stat_index(kstat_named_t *knp, ilbst_stat_t *stats, int count)
519dbed73cbSSangeeta Misra {
520dbed73cbSSangeeta Misra 	int	i;
521dbed73cbSSangeeta Misra 
522dbed73cbSSangeeta Misra 	for (i = 0; i < count; i++) {
523dbed73cbSSangeeta Misra 		if (strcasecmp(stats[i].is_name, knp->name) == 0)
524dbed73cbSSangeeta Misra 			return (i);
525dbed73cbSSangeeta Misra 	}
526dbed73cbSSangeeta Misra 
527dbed73cbSSangeeta Misra 	return (-1);
528dbed73cbSSangeeta Misra }
529dbed73cbSSangeeta Misra 
530dbed73cbSSangeeta Misra static void
i_copy_sstats(ilbst_srv_desc_t * sp,kstat_t * kp)531dbed73cbSSangeeta Misra i_copy_sstats(ilbst_srv_desc_t *sp, kstat_t *kp)
532dbed73cbSSangeeta Misra {
533dbed73cbSSangeeta Misra 	kstat_named_t	*knp;
534dbed73cbSSangeeta Misra 	int		i, ind;
535dbed73cbSSangeeta Misra 
536dbed73cbSSangeeta Misra 	knp = KSTAT_NAMED_PTR(kp);
537dbed73cbSSangeeta Misra 	for (i = 0; i < kp->ks_ndata; i++, knp++) {
538dbed73cbSSangeeta Misra 		ind = i_stat_index(knp, servstats, SSTAT_SZ);
539dbed73cbSSangeeta Misra 		if (ind == -1)
540dbed73cbSSangeeta Misra 			continue;
541dbed73cbSSangeeta Misra 		(void) strlcpy(sp->isd_serverstats[ind].is_name, knp->name,
542dbed73cbSSangeeta Misra 		    sizeof (sp->isd_serverstats[ind].is_name));
543dbed73cbSSangeeta Misra 		sp->isd_serverstats[ind].is_value = knp->value.ui64;
544dbed73cbSSangeeta Misra 		sp->isd_crtime = kp->ks_crtime;
545dbed73cbSSangeeta Misra 	}
546dbed73cbSSangeeta Misra }
547dbed73cbSSangeeta Misra 
548dbed73cbSSangeeta Misra 
549dbed73cbSSangeeta Misra static ilbadm_status_t
i_get_server_descs(ilbst_arg_t * sta,kstat_ctl_t * kctl)550dbed73cbSSangeeta Misra i_get_server_descs(ilbst_arg_t *sta, kstat_ctl_t *kctl)
551dbed73cbSSangeeta Misra {
552dbed73cbSSangeeta Misra 	ilbadm_status_t	rc = ILBADM_OK;
553dbed73cbSSangeeta Misra 	kstat_t		*kp;
554dbed73cbSSangeeta Misra 	int		i = -1;
555dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*rp;
556dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*rlist = sta->ilbst_rlist;
557dbed73cbSSangeeta Misra 	int			rcount = sta->ilbst_rcount;
558dbed73cbSSangeeta Misra 
559dbed73cbSSangeeta Misra 	/*
560dbed73cbSSangeeta Misra 	 * find all "server" kstats, or the one specified in
561dbed73cbSSangeeta Misra 	 * sta->server
562dbed73cbSSangeeta Misra 	 */
563dbed73cbSSangeeta Misra 	for (kp = kctl->kc_chain; kp != NULL; kp = kp->ks_next) {
564dbed73cbSSangeeta Misra 		if (strncmp("ilb", kp->ks_module, 3) != 0)
565dbed73cbSSangeeta Misra 			continue;
566dbed73cbSSangeeta Misra 		if (sta->ilbst_server != NULL &&
567dbed73cbSSangeeta Misra 		    strcasecmp(sta->ilbst_server, kp->ks_name) != 0)
568dbed73cbSSangeeta Misra 			continue;
569dbed73cbSSangeeta Misra 		rp = match_2_rnames(kp->ks_class, rlist, rcount);
570dbed73cbSSangeeta Misra 		if (rp == NULL)
571dbed73cbSSangeeta Misra 			continue;
572dbed73cbSSangeeta Misra 
573dbed73cbSSangeeta Misra 		(void) kstat_read(kctl, kp, NULL);
574dbed73cbSSangeeta Misra 		i = rp->ird_srv_ind++;
575dbed73cbSSangeeta Misra 
576dbed73cbSSangeeta Misra 		rc = ILBADM_OK;
577dbed73cbSSangeeta Misra 		/*
578dbed73cbSSangeeta Misra 		 * This means that a server is added after we check last
579dbed73cbSSangeeta Misra 		 * time...  Just make the array bigger.
580dbed73cbSSangeeta Misra 		 */
581dbed73cbSSangeeta Misra 		if (i+1 > rp->ird_num_servers) {
582dbed73cbSSangeeta Misra 			ilbst_srv_desc_t  *srvlist;
583dbed73cbSSangeeta Misra 
584dbed73cbSSangeeta Misra 			if ((srvlist = realloc(rp->ird_srvlist, (i+1) *
585dbed73cbSSangeeta Misra 			    sizeof (*srvlist))) == NULL) {
586dbed73cbSSangeeta Misra 				rc = ILBADM_ENOMEM;
587dbed73cbSSangeeta Misra 				break;
588dbed73cbSSangeeta Misra 			}
589dbed73cbSSangeeta Misra 			rp->ird_srvlist = srvlist;
590dbed73cbSSangeeta Misra 			rp->ird_num_servers = i;
591dbed73cbSSangeeta Misra 		}
592dbed73cbSSangeeta Misra 
593dbed73cbSSangeeta Misra 		(void) strlcpy(rp->ird_srvlist[i].isd_servername, kp->ks_name,
594dbed73cbSSangeeta Misra 		    sizeof (rp->ird_srvlist[i].isd_servername));
595dbed73cbSSangeeta Misra 		i_copy_sstats(&rp->ird_srvlist[i], kp);
596dbed73cbSSangeeta Misra 	}
597dbed73cbSSangeeta Misra 
598dbed73cbSSangeeta Misra 	for (i = 0; i < rcount; i++)
599dbed73cbSSangeeta Misra 		rlist[i].ird_srv_ind = 0;
600dbed73cbSSangeeta Misra 
601dbed73cbSSangeeta Misra 	if (sta->ilbst_server != NULL && i == -1)
602dbed73cbSSangeeta Misra 		rc = ILBADM_ENOSERVER;
603dbed73cbSSangeeta Misra 	return (rc);
604dbed73cbSSangeeta Misra }
605dbed73cbSSangeeta Misra 
606dbed73cbSSangeeta Misra static void
i_copy_rstats(ilbst_rule_desc_t * rp,kstat_t * kp)607dbed73cbSSangeeta Misra i_copy_rstats(ilbst_rule_desc_t *rp, kstat_t *kp)
608dbed73cbSSangeeta Misra {
609dbed73cbSSangeeta Misra 	kstat_named_t	*knp;
610dbed73cbSSangeeta Misra 	int		i, ind;
611dbed73cbSSangeeta Misra 
612dbed73cbSSangeeta Misra 	knp = KSTAT_NAMED_PTR(kp);
613dbed73cbSSangeeta Misra 	for (i = 0; i < kp->ks_ndata; i++, knp++) {
614dbed73cbSSangeeta Misra 		ind = i_stat_index(knp, rulestats, RSTAT_SZ);
615dbed73cbSSangeeta Misra 		if (ind == -1)
616dbed73cbSSangeeta Misra 			continue;
617dbed73cbSSangeeta Misra 
618dbed73cbSSangeeta Misra 		(void) strlcpy(rp->ird_rulestats[ind].is_name, knp->name,
619dbed73cbSSangeeta Misra 		    sizeof (rp->ird_rulestats[ind].is_name));
620dbed73cbSSangeeta Misra 		rp->ird_rulestats[ind].is_value = knp->value.ui64;
621dbed73cbSSangeeta Misra 	}
622dbed73cbSSangeeta Misra }
623dbed73cbSSangeeta Misra 
624dbed73cbSSangeeta Misra static void
i_set_rlstats_ptr(ilbst_rule_desc_t * rp,boolean_t old_is_old)625dbed73cbSSangeeta Misra i_set_rlstats_ptr(ilbst_rule_desc_t *rp, boolean_t old_is_old)
626dbed73cbSSangeeta Misra {
627dbed73cbSSangeeta Misra 	if (old_is_old) {
628dbed73cbSSangeeta Misra 		rp->ird_rulestats = rp->ird_rstats;
629dbed73cbSSangeeta Misra 		rp->ird_rulestats_o = rp->ird_rstats_o;
630dbed73cbSSangeeta Misra 	} else {
631dbed73cbSSangeeta Misra 		rp->ird_rulestats = rp->ird_rstats_o;
632dbed73cbSSangeeta Misra 		rp->ird_rulestats_o = rp->ird_rstats;
633dbed73cbSSangeeta Misra 	}
634dbed73cbSSangeeta Misra }
635dbed73cbSSangeeta Misra /*
636dbed73cbSSangeeta Misra  * this function walks the array of rules and switches pointer to old
637dbed73cbSSangeeta Misra  * and new stats as well as serverlists.
638dbed73cbSSangeeta Misra  */
639dbed73cbSSangeeta Misra static void
i_swap_rl_pointers(ilbst_arg_t * sta,int rcount)640dbed73cbSSangeeta Misra i_swap_rl_pointers(ilbst_arg_t *sta, int rcount)
641dbed73cbSSangeeta Misra {
642dbed73cbSSangeeta Misra 	int			i, tmp_num;
643dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*rlist = sta->ilbst_rlist;
644dbed73cbSSangeeta Misra 	ilbst_srv_desc_t	*tmp_srv;
645dbed73cbSSangeeta Misra 
646dbed73cbSSangeeta Misra 	for (i = 0; i < rcount; i++) {
647dbed73cbSSangeeta Misra 		/* swap srvlist pointers */
648dbed73cbSSangeeta Misra 		tmp_srv = rlist[i].ird_srvlist;
649dbed73cbSSangeeta Misra 		rlist[i].ird_srvlist = rlist[i].ird_srvlist_o;
650dbed73cbSSangeeta Misra 		rlist[i].ird_srvlist_o = tmp_srv;
651dbed73cbSSangeeta Misra 
652dbed73cbSSangeeta Misra 		/*
653dbed73cbSSangeeta Misra 		 * swap server counts - we need the old one to
654dbed73cbSSangeeta Misra 		 * save reallocation calls
655dbed73cbSSangeeta Misra 		 */
656dbed73cbSSangeeta Misra 		tmp_num = rlist[i].ird_num_servers_o;
657dbed73cbSSangeeta Misra 		rlist[i].ird_num_servers_o = rlist[i].ird_num_servers;
658dbed73cbSSangeeta Misra 		rlist[i].ird_num_servers = tmp_num;
659dbed73cbSSangeeta Misra 
660dbed73cbSSangeeta Misra 		/* preserve creation time */
661dbed73cbSSangeeta Misra 		rlist[i].ird_crtime_o = rlist[i].ird_crtime;
662dbed73cbSSangeeta Misra 
663dbed73cbSSangeeta Misra 		i_set_rlstats_ptr(&rlist[i], sta->ilbst_old_is_old);
664dbed73cbSSangeeta Misra 		rlist[i].ird_srv_ind = 0;
665dbed73cbSSangeeta Misra 	}
666dbed73cbSSangeeta Misra }
667dbed73cbSSangeeta Misra 
668dbed73cbSSangeeta Misra static void
i_init_rulelist(ilbst_arg_t * sta,int rcount)669dbed73cbSSangeeta Misra i_init_rulelist(ilbst_arg_t *sta, int rcount)
670dbed73cbSSangeeta Misra {
671dbed73cbSSangeeta Misra 	int			 i;
672dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*rlist = sta->ilbst_rlist;
673dbed73cbSSangeeta Misra 
674dbed73cbSSangeeta Misra 	for (i = 0; i < rcount; i++) {
675dbed73cbSSangeeta Misra 		rlist[i].ird_rulestats = rlist[i].ird_rstats;
676dbed73cbSSangeeta Misra 		rlist[i].ird_rulestats_o = rlist[i].ird_rstats_o;
677dbed73cbSSangeeta Misra 		rlist[i].ird_srv_ind = 0;
678dbed73cbSSangeeta Misra 	}
679dbed73cbSSangeeta Misra }
680dbed73cbSSangeeta Misra 
681dbed73cbSSangeeta Misra 
682dbed73cbSSangeeta Misra /*
683dbed73cbSSangeeta Misra  * this function searches for kstats describing individual rules and
684dbed73cbSSangeeta Misra  * saves name, # of servers, and the kstat_t * describing them (this is
685dbed73cbSSangeeta Misra  * for sta->rulename == NULL);
686dbed73cbSSangeeta Misra  * if sta->rulename != NULL, it names the rule we're looking for
687dbed73cbSSangeeta Misra  * and this function will fill in the other data (like the all_rules case)
688dbed73cbSSangeeta Misra  * Returns:	ILBADM_ENORULE	named rule not found
689dbed73cbSSangeeta Misra  *		ILBADM_ENOMEM	no mem. available
690dbed73cbSSangeeta Misra  */
691dbed73cbSSangeeta Misra static ilbadm_status_t
i_get_rule_descs(ilbst_arg_t * sta,kstat_ctl_t * kctl)692dbed73cbSSangeeta Misra i_get_rule_descs(ilbst_arg_t *sta, kstat_ctl_t *kctl)
693dbed73cbSSangeeta Misra {
694dbed73cbSSangeeta Misra 	ilbadm_status_t	rc = ILBADM_OK;
695dbed73cbSSangeeta Misra 	kstat_t		*kp;
696dbed73cbSSangeeta Misra 	kstat_named_t	*knp;
697dbed73cbSSangeeta Misra 	int		i;
698dbed73cbSSangeeta Misra 	int		num_servers;
699dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*rlist = sta->ilbst_rlist;
700dbed73cbSSangeeta Misra 	int		rcount = sta->ilbst_rcount;
701dbed73cbSSangeeta Misra 
702dbed73cbSSangeeta Misra 	/*
703dbed73cbSSangeeta Misra 	 * find all "rule" kstats, or the one specified in
704dbed73cbSSangeeta Misra 	 * sta->ilbst_rulename.
705dbed73cbSSangeeta Misra 	 */
706dbed73cbSSangeeta Misra 	for (i = 0, kp = kctl->kc_chain; i < rcount && kp != NULL;
707dbed73cbSSangeeta Misra 	    kp = kp->ks_next) {
708dbed73cbSSangeeta Misra 		if (strncmp("rulestat", kp->ks_class, 8) != 0 ||
709dbed73cbSSangeeta Misra 		    strncmp("ilb", kp->ks_module, 3) != 0)
710dbed73cbSSangeeta Misra 			continue;
711dbed73cbSSangeeta Misra 
712dbed73cbSSangeeta Misra 		(void) kstat_read(kctl, kp, NULL);
713dbed73cbSSangeeta Misra 
714dbed73cbSSangeeta Misra 		knp = kstat_data_lookup(kp, "num_servers");
715dbed73cbSSangeeta Misra 		if (knp == NULL) {
716dbed73cbSSangeeta Misra 			ilbadm_err(gettext("kstat_data_lookup() failed: %s"),
717dbed73cbSSangeeta Misra 			    strerror(errno));
718dbed73cbSSangeeta Misra 			rc = ILBADM_LIBERR;
719dbed73cbSSangeeta Misra 			break;
720dbed73cbSSangeeta Misra 		}
721dbed73cbSSangeeta Misra 		if (sta->ilbst_rulename != NULL) {
722dbed73cbSSangeeta Misra 			if (strcasecmp(kp->ks_name, sta->ilbst_rulename)
723dbed73cbSSangeeta Misra 			    != 0)
724dbed73cbSSangeeta Misra 				continue;
725dbed73cbSSangeeta Misra 		}
726dbed73cbSSangeeta Misra 		(void) strlcpy(rlist[i].ird_rulename, kp->ks_name,
727dbed73cbSSangeeta Misra 		    sizeof (rlist[i].ird_rulename));
728dbed73cbSSangeeta Misra 
729dbed73cbSSangeeta Misra 		/* only alloc the space we need, set counter here ... */
730dbed73cbSSangeeta Misra 		if (sta->ilbst_server != NULL)
731dbed73cbSSangeeta Misra 			num_servers = 1;
732dbed73cbSSangeeta Misra 		else
733dbed73cbSSangeeta Misra 			num_servers = (int)knp->value.ui64;
734dbed73cbSSangeeta Misra 
735dbed73cbSSangeeta Misra 		/* ... furthermore, only reallocate if necessary */
736dbed73cbSSangeeta Misra 		if (num_servers != rlist[i].ird_num_servers) {
737dbed73cbSSangeeta Misra 			ilbst_srv_desc_t  *srvlist;
738dbed73cbSSangeeta Misra 
739dbed73cbSSangeeta Misra 			rlist[i].ird_num_servers = num_servers;
740dbed73cbSSangeeta Misra 
741dbed73cbSSangeeta Misra 			if (rlist[i].ird_srvlist == NULL)
742dbed73cbSSangeeta Misra 				srvlist = calloc(num_servers,
743dbed73cbSSangeeta Misra 				    sizeof (*srvlist));
744dbed73cbSSangeeta Misra 			else
745dbed73cbSSangeeta Misra 				srvlist = realloc(rlist[i].ird_srvlist,
746dbed73cbSSangeeta Misra 				    sizeof (*srvlist) * num_servers);
747dbed73cbSSangeeta Misra 			if (srvlist == NULL) {
748dbed73cbSSangeeta Misra 				rc = ILBADM_ENOMEM;
749dbed73cbSSangeeta Misra 				break;
750dbed73cbSSangeeta Misra 			}
751dbed73cbSSangeeta Misra 			rlist[i].ird_srvlist = srvlist;
752dbed73cbSSangeeta Misra 		}
753dbed73cbSSangeeta Misra 		rlist[i].ird_srv_ind = 0;
754dbed73cbSSangeeta Misra 		rlist[i].ird_crtime = kp->ks_crtime;
755dbed73cbSSangeeta Misra 
756dbed73cbSSangeeta Misra 		i_copy_rstats(&rlist[i], kp);
757dbed73cbSSangeeta Misra 		i++;
758dbed73cbSSangeeta Misra 
759dbed73cbSSangeeta Misra 		/* if we know we're done, return */
760dbed73cbSSangeeta Misra 		if (sta->ilbst_rulename != NULL || i == rcount) {
761dbed73cbSSangeeta Misra 			rc = ILBADM_OK;
762dbed73cbSSangeeta Misra 			break;
763dbed73cbSSangeeta Misra 		}
764dbed73cbSSangeeta Misra 	}
765dbed73cbSSangeeta Misra 
766dbed73cbSSangeeta Misra 	if (sta->ilbst_rulename != NULL && i == 0)
767dbed73cbSSangeeta Misra 		rc = ILBADM_ENORULE;
768dbed73cbSSangeeta Misra 	return (rc);
769dbed73cbSSangeeta Misra }
770dbed73cbSSangeeta Misra 
771dbed73cbSSangeeta Misra static void
i_do_print(ilbst_arg_t * sta)772dbed73cbSSangeeta Misra i_do_print(ilbst_arg_t *sta)
773dbed73cbSSangeeta Misra {
774dbed73cbSSangeeta Misra 	int	i;
775dbed73cbSSangeeta Misra 
776dbed73cbSSangeeta Misra 	/* non-itemized display can go right ahead */
777dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & ILBST_ITEMIZE) == 0) {
778dbed73cbSSangeeta Misra 		ofmt_print(sta->ilbst_oh, sta);
779dbed73cbSSangeeta Misra 		return;
780dbed73cbSSangeeta Misra 	}
781dbed73cbSSangeeta Misra 
782dbed73cbSSangeeta Misra 	/*
783dbed73cbSSangeeta Misra 	 * rulename is given, list a line per server
784dbed73cbSSangeeta Misra 	 * here's how we do it:
785dbed73cbSSangeeta Misra 	 *	the _ITEMIZE flag indicates to the print function (called
786dbed73cbSSangeeta Misra 	 *	from ofmt_print()) to look at server [ird_srv_ind] only.
787dbed73cbSSangeeta Misra 	 */
788dbed73cbSSangeeta Misra 	if (sta->ilbst_rulename != NULL) {
789dbed73cbSSangeeta Misra 		sta->ilbst_rule_index = 0;
790dbed73cbSSangeeta Misra 		for (i = 0; i < sta->ilbst_rlist->ird_num_servers; i++) {
791dbed73cbSSangeeta Misra 			sta->ilbst_rlist->ird_srv_ind = i;
792dbed73cbSSangeeta Misra 			ofmt_print(sta->ilbst_oh, sta);
793dbed73cbSSangeeta Misra 		}
794dbed73cbSSangeeta Misra 		sta->ilbst_rlist->ird_srv_ind = 0;
795dbed73cbSSangeeta Misra 		return;
796dbed73cbSSangeeta Misra 	}
797dbed73cbSSangeeta Misra 
798dbed73cbSSangeeta Misra 	/* list one line for every rule for a given server */
799dbed73cbSSangeeta Misra 	for (i = 0; i < sta->ilbst_rcount; i++) {
800dbed73cbSSangeeta Misra 		/*
801dbed73cbSSangeeta Misra 		 * if a rule doesn't contain a given server, there's no
802dbed73cbSSangeeta Misra 		 * need to print it. Luckily, we can check that
803dbed73cbSSangeeta Misra 		 * fairly easily
804dbed73cbSSangeeta Misra 		 */
805dbed73cbSSangeeta Misra 		if (sta->ilbst_rlist[i].ird_srvlist[0].isd_servername[0] ==
806dbed73cbSSangeeta Misra 		    '\0')
807dbed73cbSSangeeta Misra 			continue;
808dbed73cbSSangeeta Misra 
809dbed73cbSSangeeta Misra 		sta->ilbst_rule_index = i;
810dbed73cbSSangeeta Misra 		sta->ilbst_rlist[i].ird_srv_ind = 0;
811dbed73cbSSangeeta Misra 		ofmt_print(sta->ilbst_oh, sta);
812dbed73cbSSangeeta Misra 	}
813dbed73cbSSangeeta Misra 	sta->ilbst_rule_index = 0;
814dbed73cbSSangeeta Misra }
815dbed73cbSSangeeta Misra 
816dbed73cbSSangeeta Misra static ilbadm_status_t
i_do_show_stats(ilbst_arg_t * sta)817dbed73cbSSangeeta Misra i_do_show_stats(ilbst_arg_t *sta)
818dbed73cbSSangeeta Misra {
819dbed73cbSSangeeta Misra 	kstat_ctl_t	*kctl;
820dbed73cbSSangeeta Misra 	kid_t		nkid;
821dbed73cbSSangeeta Misra 	int		rcount = 1, i;
822dbed73cbSSangeeta Misra 	ilbadm_status_t	rc = ILBADM_OK;
823dbed73cbSSangeeta Misra 	ilbst_rule_desc_t	*rlist, *rp;
824dbed73cbSSangeeta Misra 	boolean_t	pseudo_abs = B_FALSE; /* for first pass */
825dbed73cbSSangeeta Misra 
826dbed73cbSSangeeta Misra 	if ((kctl = kstat_open()) == NULL) {
827dbed73cbSSangeeta Misra 		ilbadm_err(gettext("kstat_open() failed: %s"), strerror(errno));
828dbed73cbSSangeeta Misra 		return (ILBADM_LIBERR);
829dbed73cbSSangeeta Misra 	}
830dbed73cbSSangeeta Misra 
831dbed73cbSSangeeta Misra 
832dbed73cbSSangeeta Misra 	if (sta->ilbst_rulename == NULL)
833dbed73cbSSangeeta Misra 		rcount = i_get_num_kinstances(kctl);
834dbed73cbSSangeeta Misra 
835dbed73cbSSangeeta Misra 	rlist = calloc(sizeof (*rlist), rcount);
836dbed73cbSSangeeta Misra 	if (rlist == NULL) {
837dbed73cbSSangeeta Misra 		rc = ILBADM_ENOMEM;
838dbed73cbSSangeeta Misra 		goto out;
839dbed73cbSSangeeta Misra 	}
840dbed73cbSSangeeta Misra 
841dbed73cbSSangeeta Misra 	sta->ilbst_old_is_old = B_TRUE;
842dbed73cbSSangeeta Misra 	sta->ilbst_rlist = rlist;
843dbed73cbSSangeeta Misra 	sta->ilbst_rcount = sta->ilbst_rcount_prev = rcount;
844dbed73cbSSangeeta Misra 	sta->ilbst_rlist_sz = rcount;
845dbed73cbSSangeeta Misra 
846dbed73cbSSangeeta Misra 	/*
847dbed73cbSSangeeta Misra 	 * in the first pass, we always print absolute numbers. We
848dbed73cbSSangeeta Misra 	 * need to remember whether we wanted abs. numbers for
849dbed73cbSSangeeta Misra 	 * other samples as well
850dbed73cbSSangeeta Misra 	 */
851dbed73cbSSangeeta Misra 	if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) == 0) {
852dbed73cbSSangeeta Misra 		sta->ilbst_flags |= ILBST_ABS_NUMBERS;
853dbed73cbSSangeeta Misra 		pseudo_abs = B_TRUE;
854dbed73cbSSangeeta Misra 	}
855dbed73cbSSangeeta Misra 
856dbed73cbSSangeeta Misra 	i_init_rulelist(sta, rcount);
857dbed73cbSSangeeta Misra 	do {
858dbed73cbSSangeeta Misra 		rc = i_get_rule_descs(sta, kctl);
859dbed73cbSSangeeta Misra 		if (rc != ILBADM_OK)
860dbed73cbSSangeeta Misra 			goto out;
861dbed73cbSSangeeta Misra 
862dbed73cbSSangeeta Misra 		rc = i_get_server_descs(sta, kctl);
863dbed73cbSSangeeta Misra 		if (rc != ILBADM_OK)
864dbed73cbSSangeeta Misra 			goto out;
865dbed73cbSSangeeta Misra 
866dbed73cbSSangeeta Misra 		i_do_print(sta);
867dbed73cbSSangeeta Misra 
868dbed73cbSSangeeta Misra 		if (sta->ilbst_count == -1 || --(sta->ilbst_count) > 0)
869dbed73cbSSangeeta Misra 			(void) sleep(sta->ilbst_interval);
870dbed73cbSSangeeta Misra 		else
871dbed73cbSSangeeta Misra 			break;
872dbed73cbSSangeeta Misra 
873dbed73cbSSangeeta Misra 		nkid = kstat_chain_update(kctl);
874dbed73cbSSangeeta Misra 		sta->ilbst_flags &= ~ILBST_RULES_CHANGED;
875dbed73cbSSangeeta Misra 		/*
876dbed73cbSSangeeta Misra 		 * we only need to continue with most of the rest of this if
877dbed73cbSSangeeta Misra 		 * the kstat chain id has changed
878dbed73cbSSangeeta Misra 		 */
879dbed73cbSSangeeta Misra 		if (nkid == 0)
880dbed73cbSSangeeta Misra 			goto swap_old_new;
881dbed73cbSSangeeta Misra 		if (nkid == -1) {
882dbed73cbSSangeeta Misra 			ilbadm_err(gettext("kstat_chain_update() failed: %s"),
883dbed73cbSSangeeta Misra 			    strerror(errno));
884dbed73cbSSangeeta Misra 			rc = ILBADM_LIBERR;
885dbed73cbSSangeeta Misra 			break;
886dbed73cbSSangeeta Misra 		}
887dbed73cbSSangeeta Misra 
888dbed73cbSSangeeta Misra 		/*
889dbed73cbSSangeeta Misra 		 * find out whether the number of rules has changed.
890dbed73cbSSangeeta Misra 		 * if so, adjust rcount and _o; if number has increased,
891dbed73cbSSangeeta Misra 		 * expand array to hold all rules.
892dbed73cbSSangeeta Misra 		 * we only shrink if rlist_sz is larger than both rcount and
893dbed73cbSSangeeta Misra 		 * rcount_prev;
894dbed73cbSSangeeta Misra 		 */
895dbed73cbSSangeeta Misra 		if (sta->ilbst_rulename == NULL)
896dbed73cbSSangeeta Misra 			rcount = i_get_num_kinstances(kctl);
897dbed73cbSSangeeta Misra 		if (rcount != sta->ilbst_rcount) {
898dbed73cbSSangeeta Misra 			sta->ilbst_flags |= ILBST_RULES_CHANGED;
899dbed73cbSSangeeta Misra 			sta->ilbst_rcount_prev = sta->ilbst_rcount;
900dbed73cbSSangeeta Misra 			sta->ilbst_rcount = rcount;
901dbed73cbSSangeeta Misra 
902dbed73cbSSangeeta Misra 			if (rcount > sta->ilbst_rcount_prev) {
903dbed73cbSSangeeta Misra 				rlist = realloc(sta->ilbst_rlist,
904dbed73cbSSangeeta Misra 				    sizeof (*sta->ilbst_rlist) * rcount);
905dbed73cbSSangeeta Misra 				if (rlist == NULL) {
906dbed73cbSSangeeta Misra 					rc = ILBADM_ENOMEM;
907dbed73cbSSangeeta Misra 					break;
908dbed73cbSSangeeta Misra 				}
909dbed73cbSSangeeta Misra 				sta->ilbst_rlist = rlist;
910dbed73cbSSangeeta Misra 				/* realloc doesn't zero out memory */
911dbed73cbSSangeeta Misra 				for (i = sta->ilbst_rcount_prev;
912dbed73cbSSangeeta Misra 				    i < rcount; i++) {
913dbed73cbSSangeeta Misra 					rp = &sta->ilbst_rlist[i];
914dbed73cbSSangeeta Misra 					bzero(rp, sizeof (*rp));
915dbed73cbSSangeeta Misra 					i_set_rlstats_ptr(rp,
916dbed73cbSSangeeta Misra 					    sta->ilbst_old_is_old);
917dbed73cbSSangeeta Misra 				}
918dbed73cbSSangeeta Misra 				/*
919dbed73cbSSangeeta Misra 				 * even if rlist_sz was > rcount, it's now
920dbed73cbSSangeeta Misra 				 * shrunk to rcount
921dbed73cbSSangeeta Misra 				 */
922dbed73cbSSangeeta Misra 				sta->ilbst_rlist_sz = sta->ilbst_rcount;
923dbed73cbSSangeeta Misra 			}
924dbed73cbSSangeeta Misra 		}
925dbed73cbSSangeeta Misra 
926dbed73cbSSangeeta Misra 		/*
927dbed73cbSSangeeta Misra 		 * we may need to shrink the allocated slots down to the
928dbed73cbSSangeeta Misra 		 * actually required number - we need to make sure we
929dbed73cbSSangeeta Misra 		 * don't delete old or new stats.
930dbed73cbSSangeeta Misra 		 */
931dbed73cbSSangeeta Misra 		if (sta->ilbst_rlist_sz > MAX(sta->ilbst_rcount,
932dbed73cbSSangeeta Misra 		    sta->ilbst_rcount_prev)) {
933dbed73cbSSangeeta Misra 			sta->ilbst_rlist_sz =
934dbed73cbSSangeeta Misra 			    MAX(sta->ilbst_rcount, sta->ilbst_rcount_prev);
935dbed73cbSSangeeta Misra 			rlist = realloc(sta->ilbst_rlist,
936dbed73cbSSangeeta Misra 			    sizeof (*sta->ilbst_rlist) * sta->ilbst_rlist_sz);
937dbed73cbSSangeeta Misra 			if (rlist == NULL) {
938dbed73cbSSangeeta Misra 				rc = ILBADM_ENOMEM;
939dbed73cbSSangeeta Misra 				break;
940dbed73cbSSangeeta Misra 			}
941dbed73cbSSangeeta Misra 			sta->ilbst_rlist = rlist;
942dbed73cbSSangeeta Misra 		}
943dbed73cbSSangeeta Misra 
944dbed73cbSSangeeta Misra 		/*
945dbed73cbSSangeeta Misra 		 * move pointers around so what used to point to "old"
946dbed73cbSSangeeta Misra 		 * stats now points to new, and vice versa
947dbed73cbSSangeeta Misra 		 * if we're printing absolute numbers, this rigmarole is
948dbed73cbSSangeeta Misra 		 * not necessary.
949dbed73cbSSangeeta Misra 		 */
950dbed73cbSSangeeta Misra swap_old_new:
951dbed73cbSSangeeta Misra 		if (pseudo_abs)
952dbed73cbSSangeeta Misra 			sta->ilbst_flags &= ~ILBST_ABS_NUMBERS;
953dbed73cbSSangeeta Misra 
954dbed73cbSSangeeta Misra 		if ((sta->ilbst_flags & ILBST_ABS_NUMBERS) == 0) {
955dbed73cbSSangeeta Misra 			sta->ilbst_old_is_old = !sta->ilbst_old_is_old;
956dbed73cbSSangeeta Misra 			i_swap_rl_pointers(sta, rcount);
957dbed73cbSSangeeta Misra 		}
958dbed73cbSSangeeta Misra 		_NOTE(CONSTCOND)
959dbed73cbSSangeeta Misra 	} while (B_TRUE);
960dbed73cbSSangeeta Misra 
961dbed73cbSSangeeta Misra out:
962dbed73cbSSangeeta Misra 	(void) kstat_close(kctl);
963dbed73cbSSangeeta Misra 	if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR))
964dbed73cbSSangeeta Misra 		ilbadm_err(ilbadm_errstr(rc));
965dbed73cbSSangeeta Misra 
966dbed73cbSSangeeta Misra 	if (sta->ilbst_rlist != NULL)
967dbed73cbSSangeeta Misra 		free(sta->ilbst_rlist);
968dbed73cbSSangeeta Misra 
969dbed73cbSSangeeta Misra 	return (rc);
970dbed73cbSSangeeta Misra }
971dbed73cbSSangeeta Misra 
972dbed73cbSSangeeta Misra /*
973dbed73cbSSangeeta Misra  * read ilb's kernel statistics and (periodically) display
974dbed73cbSSangeeta Misra  * them.
975dbed73cbSSangeeta Misra  */
976dbed73cbSSangeeta Misra /* ARGSUSED */
977dbed73cbSSangeeta Misra ilbadm_status_t
ilbadm_show_stats(int argc,char * argv[])978dbed73cbSSangeeta Misra ilbadm_show_stats(int argc, char *argv[])
979dbed73cbSSangeeta Misra {
980dbed73cbSSangeeta Misra 	ilbadm_status_t	rc;
981dbed73cbSSangeeta Misra 	int		c;
982dbed73cbSSangeeta Misra 	ilbst_arg_t	sta;
983dbed73cbSSangeeta Misra 	int		oflags = 0;
984dbed73cbSSangeeta Misra 	char		*fieldnames = stat_stdhdrs;
985dbed73cbSSangeeta Misra 	ofmt_field_t	*fields = stat_stdfields;
986dbed73cbSSangeeta Misra 	boolean_t	r_opt = B_FALSE, s_opt = B_FALSE, i_opt = B_FALSE;
987dbed73cbSSangeeta Misra 	boolean_t	o_opt = B_FALSE, p_opt = B_FALSE, t_opt = B_FALSE;
988dbed73cbSSangeeta Misra 	boolean_t	v_opt = B_FALSE, A_opt = B_FALSE, d_opt = B_FALSE;
989dbed73cbSSangeeta Misra 	ofmt_status_t	oerr;
990dbed73cbSSangeeta Misra 	ofmt_handle_t	oh = NULL;
991dbed73cbSSangeeta Misra 
992dbed73cbSSangeeta Misra 	bzero(&sta, sizeof (sta));
993dbed73cbSSangeeta Misra 	sta.ilbst_interval = 1;
994dbed73cbSSangeeta Misra 	sta.ilbst_count = 1;
995dbed73cbSSangeeta Misra 
996dbed73cbSSangeeta Misra 	while ((c = getopt(argc, argv, ":tdAr:s:ivo:p")) != -1) {
997dbed73cbSSangeeta Misra 		switch ((char)c) {
998dbed73cbSSangeeta Misra 		case 't': sta.ilbst_flags |= ILBST_TIMESTAMP_HEADER;
999dbed73cbSSangeeta Misra 			t_opt = B_TRUE;
1000dbed73cbSSangeeta Misra 			break;
1001dbed73cbSSangeeta Misra 		case 'd': sta.ilbst_flags |= ILBST_DELTA_INTERVAL;
1002dbed73cbSSangeeta Misra 			d_opt = B_TRUE;
1003dbed73cbSSangeeta Misra 			break;
1004dbed73cbSSangeeta Misra 		case 'A': sta.ilbst_flags |= ILBST_ABS_NUMBERS;
1005dbed73cbSSangeeta Misra 			A_opt = B_TRUE;
1006dbed73cbSSangeeta Misra 			break;
1007dbed73cbSSangeeta Misra 		case 'r': sta.ilbst_rulename = optarg;
1008dbed73cbSSangeeta Misra 			r_opt = B_TRUE;
1009dbed73cbSSangeeta Misra 			break;
1010dbed73cbSSangeeta Misra 		case 's': sta.ilbst_server = optarg;
1011dbed73cbSSangeeta Misra 			s_opt = B_TRUE;
1012dbed73cbSSangeeta Misra 			break;
1013dbed73cbSSangeeta Misra 		case 'i': sta.ilbst_flags |= ILBST_ITEMIZE;
1014dbed73cbSSangeeta Misra 			i_opt = B_TRUE;
1015dbed73cbSSangeeta Misra 			break;
1016dbed73cbSSangeeta Misra 		case 'o': fieldnames = optarg;
1017dbed73cbSSangeeta Misra 			o_opt = B_TRUE;
1018dbed73cbSSangeeta Misra 			break;
1019dbed73cbSSangeeta Misra 		case 'p': oflags |= OFMT_PARSABLE;
1020dbed73cbSSangeeta Misra 			p_opt = B_TRUE;
1021dbed73cbSSangeeta Misra 			break;
1022dbed73cbSSangeeta Misra 		case 'v': sta.ilbst_flags |= ILBST_VERBOSE;
1023dbed73cbSSangeeta Misra 			v_opt = B_TRUE;
1024dbed73cbSSangeeta Misra 			fieldnames = stat_stdv_hdrs;
1025dbed73cbSSangeeta Misra 			break;
1026dbed73cbSSangeeta Misra 		case ':': ilbadm_err(gettext("missing option-argument"
1027dbed73cbSSangeeta Misra 			    " detected for %c"), (char)optopt);
1028dbed73cbSSangeeta Misra 			exit(1);
1029dbed73cbSSangeeta Misra 			/* not reached */
1030dbed73cbSSangeeta Misra 			break;
1031dbed73cbSSangeeta Misra 		case '?': /* fallthrough */
1032dbed73cbSSangeeta Misra 		default:
1033dbed73cbSSangeeta Misra 			unknown_opt(argv, optind-1);
1034dbed73cbSSangeeta Misra 			/* not reached */
1035dbed73cbSSangeeta Misra 			break;
1036dbed73cbSSangeeta Misra 		}
1037dbed73cbSSangeeta Misra 	}
1038dbed73cbSSangeeta Misra 
1039dbed73cbSSangeeta Misra 	if (s_opt && r_opt) {
1040dbed73cbSSangeeta Misra 		ilbadm_err(gettext("options -s and -r are mutually exclusive"));
1041dbed73cbSSangeeta Misra 		exit(1);
1042dbed73cbSSangeeta Misra 	}
1043dbed73cbSSangeeta Misra 
1044dbed73cbSSangeeta Misra 	if (i_opt) {
1045dbed73cbSSangeeta Misra 		if (!(s_opt || r_opt)) {
1046dbed73cbSSangeeta Misra 			ilbadm_err(gettext("option -i requires"
1047dbed73cbSSangeeta Misra 			    " either -r or -s"));
1048dbed73cbSSangeeta Misra 			exit(1);
1049dbed73cbSSangeeta Misra 		}
1050dbed73cbSSangeeta Misra 		if (v_opt) {
1051dbed73cbSSangeeta Misra 			ilbadm_err(gettext("option -i and -v are mutually"
1052dbed73cbSSangeeta Misra 			    " exclusive"));
1053dbed73cbSSangeeta Misra 			exit(1);
1054dbed73cbSSangeeta Misra 		}
1055dbed73cbSSangeeta Misra 		/* only use "std" headers if none are specified */
1056dbed73cbSSangeeta Misra 		if (!o_opt)
1057dbed73cbSSangeeta Misra 			if (r_opt)
1058dbed73cbSSangeeta Misra 				fieldnames = stat_itemize_rule_hdrs;
1059dbed73cbSSangeeta Misra 			else /* must be s_opt */
1060dbed73cbSSangeeta Misra 				fieldnames = stat_itemize_server_hdrs;
1061dbed73cbSSangeeta Misra 		fields = stat_itemize_fields;
1062dbed73cbSSangeeta Misra 	}
1063dbed73cbSSangeeta Misra 
1064dbed73cbSSangeeta Misra 	if (p_opt) {
1065dbed73cbSSangeeta Misra 		if (!o_opt) {
1066dbed73cbSSangeeta Misra 			ilbadm_err(gettext("option -p requires -o"));
1067dbed73cbSSangeeta Misra 			exit(1);
1068dbed73cbSSangeeta Misra 		}
1069dbed73cbSSangeeta Misra 		if (v_opt) {
1070dbed73cbSSangeeta Misra 			ilbadm_err(gettext("option -o and -v are mutually"
1071dbed73cbSSangeeta Misra 			    " exclusive"));
1072dbed73cbSSangeeta Misra 			exit(1);
1073dbed73cbSSangeeta Misra 		}
1074dbed73cbSSangeeta Misra 		if (strcasecmp(fieldnames, "all") == 0) {
1075dbed73cbSSangeeta Misra 			ilbadm_err(gettext("option -p requires"
1076dbed73cbSSangeeta Misra 			    " explicit field names"));
1077dbed73cbSSangeeta Misra 			exit(1);
1078dbed73cbSSangeeta Misra 		}
1079dbed73cbSSangeeta Misra 	}
1080dbed73cbSSangeeta Misra 
1081dbed73cbSSangeeta Misra 	if (t_opt) {
1082dbed73cbSSangeeta Misra 		if (v_opt) {
1083dbed73cbSSangeeta Misra 			fieldnames = "all";
1084dbed73cbSSangeeta Misra 		} else {
1085dbed73cbSSangeeta Misra 			int  len = strlen(fieldnames) + 6;
1086dbed73cbSSangeeta Misra 			char *fnames;
1087dbed73cbSSangeeta Misra 
1088dbed73cbSSangeeta Misra 			fnames = malloc(len);
1089dbed73cbSSangeeta Misra 			if (fnames == NULL) {
1090dbed73cbSSangeeta Misra 				rc = ILBADM_ENOMEM;
1091dbed73cbSSangeeta Misra 				return (rc);
1092dbed73cbSSangeeta Misra 			}
1093dbed73cbSSangeeta Misra 			(void) snprintf(fnames, len, "%s,TIME", fieldnames);
1094dbed73cbSSangeeta Misra 			fieldnames = fnames;
1095dbed73cbSSangeeta Misra 		}
1096dbed73cbSSangeeta Misra 	}
1097dbed73cbSSangeeta Misra 
1098dbed73cbSSangeeta Misra 	if (A_opt && d_opt) {
1099dbed73cbSSangeeta Misra 		ilbadm_err(gettext("options -d and -A are mutually exclusive"));
1100dbed73cbSSangeeta Misra 		exit(1);
1101dbed73cbSSangeeta Misra 	}
1102dbed73cbSSangeeta Misra 
1103dbed73cbSSangeeta Misra 	/* find and parse interval and count arguments if present */
1104dbed73cbSSangeeta Misra 	if (optind < argc) {
1105dbed73cbSSangeeta Misra 		sta.ilbst_interval = atoi(argv[optind]);
1106dbed73cbSSangeeta Misra 		if (sta.ilbst_interval < 1) {
1107dbed73cbSSangeeta Misra 			ilbadm_err(gettext("illegal interval spec %s"),
1108dbed73cbSSangeeta Misra 			    argv[optind]);
1109dbed73cbSSangeeta Misra 			exit(1);
1110dbed73cbSSangeeta Misra 		}
1111dbed73cbSSangeeta Misra 		sta.ilbst_count = -1;
1112dbed73cbSSangeeta Misra 		if (++optind < argc) {
1113dbed73cbSSangeeta Misra 			sta.ilbst_count = atoi(argv[optind]);
1114dbed73cbSSangeeta Misra 			if (sta.ilbst_count < 1) {
1115dbed73cbSSangeeta Misra 				ilbadm_err(gettext("illegal count spec %s"),
1116dbed73cbSSangeeta Misra 				    argv[optind]);
1117dbed73cbSSangeeta Misra 				exit(1);
1118dbed73cbSSangeeta Misra 			}
1119dbed73cbSSangeeta Misra 		}
1120dbed73cbSSangeeta Misra 	}
1121dbed73cbSSangeeta Misra 
1122dbed73cbSSangeeta Misra 	oerr = ofmt_open(fieldnames, fields, oflags, 80, &oh);
1123dbed73cbSSangeeta Misra 	if (oerr != OFMT_SUCCESS) {
1124dbed73cbSSangeeta Misra 		char	e[80];
1125dbed73cbSSangeeta Misra 
1126dbed73cbSSangeeta Misra 		ilbadm_err(gettext("ofmt_open failed: %s"),
1127dbed73cbSSangeeta Misra 		    ofmt_strerror(oh, oerr, e, sizeof (e)));
1128dbed73cbSSangeeta Misra 		return (ILBADM_LIBERR);
1129dbed73cbSSangeeta Misra 	}
1130dbed73cbSSangeeta Misra 
1131dbed73cbSSangeeta Misra 	sta.ilbst_oh = oh;
1132dbed73cbSSangeeta Misra 
1133dbed73cbSSangeeta Misra 	rc = i_do_show_stats(&sta);
1134dbed73cbSSangeeta Misra 
1135dbed73cbSSangeeta Misra 	ofmt_close(oh);
1136dbed73cbSSangeeta Misra 	return (rc);
1137dbed73cbSSangeeta Misra }
1138