Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.sbin / altq / tbrconfig / tbrconfig.c
blob1e70d24e1947b1d9e9a1394eeff2f1d36d8b14c6
1 /* $NetBSD$ */
2 /* $KAME: tbrconfig.c,v 1.3 2001/05/08 04:36:39 itojun Exp $ */
3 /*
4 * Copyright (C) 2000
5 * Sony Computer Science Laboratories Inc. All rights reserved.
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.
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.
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <sys/fcntl.h>
34 #include <sys/sysctl.h>
35 #include <net/if.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <err.h>
43 #include <altq/altq.h>
45 #define ALTQ_DEVICE "/dev/altq/altq"
47 static void usage(void);
48 static u_long atobps(const char *s);
49 static u_long atobytes(const char *s);
50 static u_int size_bucket(const char *ifname, const u_int rate);
51 static u_int autosize_bucket(const char *ifname, const u_int rate);
52 static int get_clockfreq(void);
53 static int get_ifmtu(const char *ifname);
54 static void list_all(void);
56 static void
57 usage(void)
59 fprintf(stderr, "usage: tbrconfig interface [tokenrate [bucketsize]\n");
60 fprintf(stderr, " tbrconfig -d interface\n");
61 fprintf(stderr, " tbrconfig -a\n");
62 exit(1);
65 int
66 main(int argc, char **argv)
68 struct tbrreq req;
69 u_int rate, depth;
70 int fd, ch, delete;
72 delete = 0;
73 rate = 0;
74 depth = 0;
76 while ((ch = getopt(argc, argv, "ad")) != -1) {
77 switch (ch) {
78 case 'a':
79 list_all();
80 return (0);
81 case 'd':
82 delete = 1;
83 break;
87 argc -= optind;
88 argv += optind;
89 if (argc < 1)
90 usage();
92 req.ifname[IFNAMSIZ-1] = '\0';
93 strncpy(req.ifname, argv[0], IFNAMSIZ-1);
94 if (argc > 1)
95 rate = (u_int)atobps(argv[1]);
96 if (argc > 2) {
97 if (strncmp(argv[2], "auto", strlen("auto")) == 0)
98 depth = autosize_bucket(req.ifname, rate);
99 else
100 depth = (u_int)atobytes(argv[2]);
102 if (argc > 3)
103 usage();
105 if (delete || rate > 0) {
106 /* set token bucket regulator */
107 if (delete)
108 rate = 0;
109 else if (depth == 0)
110 depth = size_bucket(req.ifname, rate);
112 req.tb_prof.rate = rate;
113 req.tb_prof.depth = depth;
115 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0)
116 err(1, "can't open altq device");
118 if (ioctl(fd, ALTQTBRSET, &req) < 0)
119 err(1, "ALTQTBRSET for interface %s", req.ifname);
121 close(fd);
123 if (delete) {
124 printf("deleted token bucket regulator on %s\n",
125 req.ifname);
126 return (0);
130 /* get token bucket regulator */
131 if ((fd = open(ALTQ_DEVICE, O_RDONLY)) < 0)
132 err(1, "can't open altq device");
133 if (ioctl(fd, ALTQTBRGET, &req) < 0)
134 err(1, "ALTQTBRGET for interface %s", req.ifname);
135 if (req.tb_prof.rate == 0)
136 printf("no token bucket regulater found on %s\n", req.ifname);
137 else {
138 char rate_str[64], size_str[64];
140 if (req.tb_prof.rate < 999999)
141 sprintf(rate_str, "%.2fK",
142 (double)req.tb_prof.rate/1000.0);
143 else
144 sprintf(rate_str, "%.2fM",
145 (double)req.tb_prof.rate/1000000.0);
146 if (req.tb_prof.depth < 10240)
147 sprintf(size_str, "%u", req.tb_prof.depth);
148 else
149 sprintf(size_str, "%.2fK",
150 (double)req.tb_prof.depth/1024.0);
151 printf("%s: tokenrate %s(bps) bucketsize %s(bytes)\n",
152 req.ifname, rate_str, size_str);
154 close(fd);
155 return (0);
158 static void
159 list_all(void)
161 struct if_nameindex *ifn_list, *ifnp;
162 struct tbrreq req;
163 char rate_str[64], size_str[64];
164 int fd, ntbr;
166 if ((ifn_list = if_nameindex()) == NULL)
167 err(1, "if_nameindex failed");
169 if ((fd = open(ALTQ_DEVICE, O_RDONLY)) < 0)
170 err(1, "can't open altq device");
172 ntbr = 0;
173 for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) {
174 req.ifname[IFNAMSIZ-1] = '\0';
175 strncpy(req.ifname, ifnp->if_name, IFNAMSIZ-1);
176 if (ioctl(fd, ALTQTBRGET, &req) < 0)
177 err(1, "ALTQTBRGET");
178 if (req.tb_prof.rate == 0)
179 continue;
181 if (req.tb_prof.rate < 999999)
182 sprintf(rate_str, "%.2fK",
183 (double)req.tb_prof.rate/1000.0);
184 else
185 sprintf(rate_str, "%.2fM",
186 (double)req.tb_prof.rate/1000000.0);
187 if (req.tb_prof.depth < 10240)
188 sprintf(size_str, "%u", req.tb_prof.depth);
189 else
190 sprintf(size_str, "%.2fK",
191 (double)req.tb_prof.depth/1024.0);
192 printf("%s: tokenrate %s(bps) bucketsize %s(bytes)\n",
193 req.ifname, rate_str, size_str);
194 ntbr++;
196 if (ntbr == 0)
197 printf("no active token bucket regulator\n");
199 close(fd);
200 if_freenameindex(ifn_list);
203 static u_long
204 atobps(const char *s)
206 u_long bandwidth;
207 char *cp;
209 bandwidth = strtoul(s, &cp, 0);
210 if (cp != NULL) {
211 if (*cp == 'K' || *cp == 'k')
212 bandwidth *= 1000;
213 else if (*cp == 'M' || *cp == 'm')
214 bandwidth *= 1000000;
215 else if (*cp == 'G' || *cp == 'g')
216 bandwidth *= 1000000000;
218 return (bandwidth);
221 static u_long
222 atobytes(const char *s)
224 u_long bytes;
225 char *cp;
227 bytes = strtoul(s, &cp, 0);
228 if (cp != NULL) {
229 if (*cp == 'K' || *cp == 'k')
230 bytes *= 1024;
231 else if (*cp == 'M' || *cp == 'm')
232 bytes *= 1024 * 1024;
233 else if (*cp == 'G' || *cp == 'g')
234 bytes *= 1024 * 1024 * 1024;
236 return (bytes);
240 * use heuristics to determin the bucket size
242 static u_int
243 size_bucket(const char *ifname, const u_int rate)
245 u_int size, mtu;
247 mtu = get_ifmtu(ifname);
248 if (mtu > 1500)
249 mtu = 1500; /* assume that the path mtu is still 1500 */
251 if (rate <= 1*1000*1000)
252 size = 1;
253 else if (rate <= 10*1000*1000)
254 size = 4;
255 else if (rate <= 200*1000*1000)
256 size = 8;
257 else
258 size = 24;
260 size = size * mtu;
261 return (size);
265 * compute the bucket size to be required to fill the rate
266 * even when the rate is controlled only by the kernel timer.
268 static u_int
269 autosize_bucket(const char *ifname, const u_int rate)
271 u_int size, freq, mtu;
273 mtu = get_ifmtu(ifname);
274 freq = get_clockfreq();
275 size = rate / 8 / freq;
276 if (size < mtu)
277 size = mtu;
278 return (size);
281 static int
282 get_clockfreq(void)
284 struct clockinfo clkinfo;
285 int mib[2];
286 size_t len;
288 clkinfo.hz = 100; /* default Hz */
290 mib[0] = CTL_KERN;
291 mib[1] = KERN_CLOCKRATE;
292 len = sizeof(struct clockinfo);
293 if (sysctl(mib, 2, &clkinfo, &len, NULL, 0) == -1)
294 warnx("can't get clockrate via sysctl! use %dHz", clkinfo.hz);
295 return (clkinfo.hz);
298 static int
299 get_ifmtu(const char *ifname)
301 int s, mtu;
302 struct ifreq ifr;
303 #ifdef __OpenBSD__
304 struct if_data ifdata;
305 #endif
307 mtu = 512; /* default MTU */
309 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
310 return (mtu);
311 strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
312 #ifdef __OpenBSD__
313 ifr.ifr_data = (caddr_t)&ifdata;
314 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0)
315 mtu = ifdata.ifi_mtu;
316 #else
317 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0)
318 mtu = ifr.ifr_mtu;
319 #endif
320 close(s);
321 return (mtu);