1/*	$NetBSD: altqstat.c,v 1.7 2006/10/28 11:43:02 peter Exp $	*/
2/*	$KAME: altqstat.c,v 1.8 2002/10/27 03:19:35 kjc Exp $	*/
3/*
4 * Copyright (C) 1999-2000
5 *	Sony Computer Science Laboratories, Inc.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/time.h>
31#include <sys/fcntl.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <string.h>
37#include <signal.h>
38#include <errno.h>
39#include <err.h>
40#ifndef NO_CURSES
41#include <curses.h>
42#endif
43
44#include "quip_client.h"
45#include "altqstat.h"
46
47#define DEV_PATH	"/dev/altq"
48
49int qdiscfd = -1;
50int show_config = 0;
51double ival = 5.0;
52int no_server = 0;
53char *interface = NULL;
54char *qdisc_name = NULL;
55
56stat_loop_t *stat_loop;
57
58__dead static void sig_handler(int);
59static void alrm_handler(int);
60__dead static void usage(void);
61
62static void
63sig_handler(int sig)
64{
65	char buf[8192];
66
67	snprintf(buf, sizeof buf, "Exiting on signal %d\n", sig);
68	write(STDERR_FILENO, buf, strlen(buf));
69
70#ifndef NO_CURSES
71	/* XXX signal race */
72	if (qdisc_name != NULL && strcmp(qdisc_name, "wfq") == 0)
73		endwin();	/* wfqstat uses curses */
74#endif
75	_exit(0);
76}
77
78static void
79alrm_handler(int sig)
80{
81	/* nothing */
82}
83
84static void
85usage(void)
86{
87	fprintf(stderr, "usage: altqstat [-enrs] [-c count] [-w wait] [-i interface|-I input_interface]\n");
88	exit(1);
89}
90
91int
92main (int argc, char **argv)
93{
94	int ch, raw_mode = 0;
95	int qtype, interval;
96	int count = 0;
97	struct itimerval it;
98	char device[64], qname[64], input[32];
99
100	while ((ch = getopt(argc, argv, "I:c:ei:nrsw:")) != -1) {
101		switch (ch) {
102		case 'I':
103			snprintf(input, sizeof(input), "_%s", optarg);
104			interface = input;
105			break;
106		case 'c':
107			count = atoi(optarg);
108			if (count < 1)
109				errx(1, "Please supply a count value bigger than 0.");
110			break;
111		case 'e':
112			quip_echo = 1;
113			break;
114		case 'i':
115			interface = optarg;
116			break;
117		case 'n':
118			no_server = 1;
119			break;
120		case 'r':
121			raw_mode = 1;
122			quip_echo = 1;
123			break;
124		case 's':
125			show_config = 1;
126			break;
127		case 'w':
128			ival = strtod(optarg, NULL);
129			break;
130		default:
131			usage();
132			break;
133		}
134	}
135
136	signal(SIGINT, sig_handler);
137	signal(SIGTERM, sig_handler);
138	signal(SIGPIPE, sig_handler);
139	signal(SIGALRM, alrm_handler);
140
141	if (no_server == 0) {
142		if (quip_openserver() < 0 && interface == NULL)
143			errx(1, "you have to specify interface!");
144	}
145
146	if (raw_mode == 1) {
147		quip_rawmode();
148		quip_closeserver();
149		exit(0);
150	}
151
152	if (show_config) {
153		if (no_server)
154			errx(1, "no server (-n) can't be set for show config (-s)!");
155		quip_printconfig();
156		quip_closeserver();
157		exit(0);
158	}
159
160	interface = quip_selectinterface(interface);
161	if (interface == NULL)
162		errx(1, "no interface found!");
163
164	qtype = ifname2qdisc(interface, qname);
165	if (qtype == 0)
166		errx(1, "altq is not attached on %s!", interface);
167
168	qdisc_name = qname;
169
170	stat_loop = qdisc2stat_loop(qdisc_name);
171	if (stat_loop == NULL)
172		errx(1, "qdisc %s is not supported!", qdisc_name);
173
174	printf("%s: %s on interface %s\n",
175	       argv[0], qdisc_name, interface);
176
177	snprintf(device, sizeof(device), "%s/%s", DEV_PATH, qdisc_name);
178	if ((qdiscfd = open(device, O_RDONLY)) < 0)
179		err(1, "can't open %s", device);
180
181	interval = (int)(ival * 1000.0);
182	it.it_interval.tv_sec = interval / 1000;
183	it.it_interval.tv_usec = interval % 1000 * 1000;
184	it.it_value = it.it_interval;
185	setitimer(ITIMER_REAL, &it, NULL);
186
187	(*stat_loop)(qdiscfd, interface, count, (int)ival);
188
189	exit(0);
190}
191
192/* calculate interval in sec */
193double
194calc_interval(struct timeval *cur_time, struct timeval *last_time)
195{
196	double sec;
197
198	sec = (double)(cur_time->tv_sec - last_time->tv_sec) +
199	    (double)(cur_time->tv_usec - last_time->tv_usec) / 1000000;
200	return (sec);
201}
202
203
204/* calculate rate in bps */
205double
206calc_rate(u_int64_t new_bytes, u_int64_t last_bytes, double interval)
207{
208	double rate;
209
210	rate = (double)(new_bytes - last_bytes) * 8 / interval;
211	return (rate);
212}
213
214/* calculate packets in second */
215double
216calc_pps(u_int64_t new_pkts, u_int64_t last_pkts, double interval)
217{
218	double pps;
219
220	pps = (double)(new_pkts - last_pkts) / interval;
221	return (pps);
222}
223
224#define	R2S_BUFS	8
225#define	RATESTR_MAX	16
226char *
227rate2str(double rate)
228{
229	char *buf;
230	static char r2sbuf[R2S_BUFS][RATESTR_MAX];  /* ring bufer */
231	static int idx = 0;
232
233	buf = r2sbuf[idx++];
234	if (idx == R2S_BUFS)
235		idx = 0;
236
237	if (rate == 0.0)
238		snprintf(buf, RATESTR_MAX, "0");
239	else if (rate >= 1000000.0)
240		snprintf(buf, RATESTR_MAX, "%.2fM", rate / 1000000.0);
241	else
242		snprintf(buf, RATESTR_MAX, "%.2fk", rate / 1000.0);
243	return (buf);
244}
245