1 1.5 andvar /* $NetBSD: tbrconfig.c,v 1.5 2023/08/03 20:45:50 andvar Exp $ */ 2 1.2 itojun /* $KAME: tbrconfig.c,v 1.3 2001/05/08 04:36:39 itojun Exp $ */ 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (C) 2000 5 1.1 thorpej * Sony Computer Science Laboratories Inc. All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Redistribution and use in source and binary forms, with or without 8 1.1 thorpej * modification, are permitted provided that the following conditions 9 1.1 thorpej * are met: 10 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 11 1.1 thorpej * notice, this list of conditions and the following disclaimer. 12 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 14 1.1 thorpej * documentation and/or other materials provided with the distribution. 15 1.1 thorpej * 16 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 17 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 20 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 thorpej * SUCH DAMAGE. 27 1.1 thorpej */ 28 1.1 thorpej 29 1.1 thorpej #include <sys/param.h> 30 1.1 thorpej #include <sys/time.h> 31 1.1 thorpej #include <sys/socket.h> 32 1.1 thorpej #include <sys/ioctl.h> 33 1.1 thorpej #include <sys/fcntl.h> 34 1.1 thorpej #include <sys/sysctl.h> 35 1.1 thorpej #include <net/if.h> 36 1.1 thorpej 37 1.1 thorpej #include <stdio.h> 38 1.1 thorpej #include <stdlib.h> 39 1.1 thorpej #include <unistd.h> 40 1.1 thorpej #include <string.h> 41 1.1 thorpej #include <err.h> 42 1.1 thorpej 43 1.1 thorpej #include <altq/altq.h> 44 1.1 thorpej 45 1.1 thorpej #define ALTQ_DEVICE "/dev/altq/altq" 46 1.1 thorpej 47 1.4 joerg __dead static void usage(void); 48 1.1 thorpej static u_long atobps(const char *s); 49 1.1 thorpej static u_long atobytes(const char *s); 50 1.1 thorpej static u_int size_bucket(const char *ifname, const u_int rate); 51 1.1 thorpej static u_int autosize_bucket(const char *ifname, const u_int rate); 52 1.1 thorpej static int get_clockfreq(void); 53 1.1 thorpej static int get_ifmtu(const char *ifname); 54 1.1 thorpej static void list_all(void); 55 1.1 thorpej 56 1.1 thorpej static void 57 1.1 thorpej usage(void) 58 1.1 thorpej { 59 1.1 thorpej fprintf(stderr, "usage: tbrconfig interface [tokenrate [bucketsize]\n"); 60 1.1 thorpej fprintf(stderr, " tbrconfig -d interface\n"); 61 1.1 thorpej fprintf(stderr, " tbrconfig -a\n"); 62 1.1 thorpej exit(1); 63 1.1 thorpej } 64 1.1 thorpej 65 1.1 thorpej int 66 1.1 thorpej main(int argc, char **argv) 67 1.1 thorpej { 68 1.1 thorpej struct tbrreq req; 69 1.1 thorpej u_int rate, depth; 70 1.1 thorpej int fd, ch, delete; 71 1.1 thorpej 72 1.1 thorpej delete = 0; 73 1.1 thorpej rate = 0; 74 1.1 thorpej depth = 0; 75 1.1 thorpej 76 1.2 itojun while ((ch = getopt(argc, argv, "ad")) != -1) { 77 1.1 thorpej switch (ch) { 78 1.1 thorpej case 'a': 79 1.1 thorpej list_all(); 80 1.1 thorpej return (0); 81 1.1 thorpej case 'd': 82 1.1 thorpej delete = 1; 83 1.1 thorpej break; 84 1.1 thorpej } 85 1.1 thorpej } 86 1.1 thorpej 87 1.1 thorpej argc -= optind; 88 1.1 thorpej argv += optind; 89 1.1 thorpej if (argc < 1) 90 1.1 thorpej usage(); 91 1.1 thorpej 92 1.1 thorpej req.ifname[IFNAMSIZ-1] = '\0'; 93 1.1 thorpej strncpy(req.ifname, argv[0], IFNAMSIZ-1); 94 1.1 thorpej if (argc > 1) 95 1.1 thorpej rate = (u_int)atobps(argv[1]); 96 1.1 thorpej if (argc > 2) { 97 1.1 thorpej if (strncmp(argv[2], "auto", strlen("auto")) == 0) 98 1.1 thorpej depth = autosize_bucket(req.ifname, rate); 99 1.1 thorpej else 100 1.1 thorpej depth = (u_int)atobytes(argv[2]); 101 1.1 thorpej } 102 1.1 thorpej if (argc > 3) 103 1.1 thorpej usage(); 104 1.1 thorpej 105 1.1 thorpej if (delete || rate > 0) { 106 1.1 thorpej /* set token bucket regulator */ 107 1.1 thorpej if (delete) 108 1.1 thorpej rate = 0; 109 1.1 thorpej else if (depth == 0) 110 1.1 thorpej depth = size_bucket(req.ifname, rate); 111 1.1 thorpej 112 1.1 thorpej req.tb_prof.rate = rate; 113 1.1 thorpej req.tb_prof.depth = depth; 114 1.1 thorpej 115 1.1 thorpej if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 116 1.1 thorpej err(1, "can't open altq device"); 117 1.1 thorpej 118 1.1 thorpej if (ioctl(fd, ALTQTBRSET, &req) < 0) 119 1.1 thorpej err(1, "ALTQTBRSET for interface %s", req.ifname); 120 1.1 thorpej 121 1.1 thorpej close(fd); 122 1.1 thorpej 123 1.1 thorpej if (delete) { 124 1.1 thorpej printf("deleted token bucket regulator on %s\n", 125 1.1 thorpej req.ifname); 126 1.1 thorpej return (0); 127 1.1 thorpej } 128 1.1 thorpej } 129 1.1 thorpej 130 1.1 thorpej /* get token bucket regulator */ 131 1.1 thorpej if ((fd = open(ALTQ_DEVICE, O_RDONLY)) < 0) 132 1.1 thorpej err(1, "can't open altq device"); 133 1.1 thorpej if (ioctl(fd, ALTQTBRGET, &req) < 0) 134 1.1 thorpej err(1, "ALTQTBRGET for interface %s", req.ifname); 135 1.1 thorpej if (req.tb_prof.rate == 0) 136 1.1 thorpej printf("no token bucket regulater found on %s\n", req.ifname); 137 1.1 thorpej else { 138 1.1 thorpej char rate_str[64], size_str[64]; 139 1.1 thorpej 140 1.1 thorpej if (req.tb_prof.rate < 999999) 141 1.1 thorpej sprintf(rate_str, "%.2fK", 142 1.1 thorpej (double)req.tb_prof.rate/1000.0); 143 1.1 thorpej else 144 1.1 thorpej sprintf(rate_str, "%.2fM", 145 1.1 thorpej (double)req.tb_prof.rate/1000000.0); 146 1.1 thorpej if (req.tb_prof.depth < 10240) 147 1.1 thorpej sprintf(size_str, "%u", req.tb_prof.depth); 148 1.1 thorpej else 149 1.1 thorpej sprintf(size_str, "%.2fK", 150 1.1 thorpej (double)req.tb_prof.depth/1024.0); 151 1.1 thorpej printf("%s: tokenrate %s(bps) bucketsize %s(bytes)\n", 152 1.1 thorpej req.ifname, rate_str, size_str); 153 1.1 thorpej } 154 1.1 thorpej close(fd); 155 1.1 thorpej return (0); 156 1.1 thorpej } 157 1.1 thorpej 158 1.1 thorpej static void 159 1.1 thorpej list_all(void) 160 1.1 thorpej { 161 1.1 thorpej struct if_nameindex *ifn_list, *ifnp; 162 1.1 thorpej struct tbrreq req; 163 1.1 thorpej char rate_str[64], size_str[64]; 164 1.1 thorpej int fd, ntbr; 165 1.1 thorpej 166 1.1 thorpej if ((ifn_list = if_nameindex()) == NULL) 167 1.1 thorpej err(1, "if_nameindex failed"); 168 1.1 thorpej 169 1.1 thorpej if ((fd = open(ALTQ_DEVICE, O_RDONLY)) < 0) 170 1.1 thorpej err(1, "can't open altq device"); 171 1.1 thorpej 172 1.1 thorpej ntbr = 0; 173 1.1 thorpej for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) { 174 1.1 thorpej req.ifname[IFNAMSIZ-1] = '\0'; 175 1.1 thorpej strncpy(req.ifname, ifnp->if_name, IFNAMSIZ-1); 176 1.1 thorpej if (ioctl(fd, ALTQTBRGET, &req) < 0) 177 1.1 thorpej err(1, "ALTQTBRGET"); 178 1.1 thorpej if (req.tb_prof.rate == 0) 179 1.1 thorpej continue; 180 1.1 thorpej 181 1.1 thorpej if (req.tb_prof.rate < 999999) 182 1.1 thorpej sprintf(rate_str, "%.2fK", 183 1.1 thorpej (double)req.tb_prof.rate/1000.0); 184 1.1 thorpej else 185 1.1 thorpej sprintf(rate_str, "%.2fM", 186 1.1 thorpej (double)req.tb_prof.rate/1000000.0); 187 1.1 thorpej if (req.tb_prof.depth < 10240) 188 1.1 thorpej sprintf(size_str, "%u", req.tb_prof.depth); 189 1.1 thorpej else 190 1.1 thorpej sprintf(size_str, "%.2fK", 191 1.1 thorpej (double)req.tb_prof.depth/1024.0); 192 1.1 thorpej printf("%s: tokenrate %s(bps) bucketsize %s(bytes)\n", 193 1.1 thorpej req.ifname, rate_str, size_str); 194 1.1 thorpej ntbr++; 195 1.1 thorpej } 196 1.1 thorpej if (ntbr == 0) 197 1.1 thorpej printf("no active token bucket regulator\n"); 198 1.1 thorpej 199 1.1 thorpej close(fd); 200 1.1 thorpej if_freenameindex(ifn_list); 201 1.1 thorpej } 202 1.1 thorpej 203 1.1 thorpej static u_long 204 1.1 thorpej atobps(const char *s) 205 1.1 thorpej { 206 1.1 thorpej u_long bandwidth; 207 1.1 thorpej char *cp; 208 1.1 thorpej 209 1.1 thorpej bandwidth = strtoul(s, &cp, 0); 210 1.1 thorpej if (cp != NULL) { 211 1.1 thorpej if (*cp == 'K' || *cp == 'k') 212 1.1 thorpej bandwidth *= 1000; 213 1.1 thorpej else if (*cp == 'M' || *cp == 'm') 214 1.1 thorpej bandwidth *= 1000000; 215 1.1 thorpej else if (*cp == 'G' || *cp == 'g') 216 1.1 thorpej bandwidth *= 1000000000; 217 1.1 thorpej } 218 1.1 thorpej return (bandwidth); 219 1.1 thorpej } 220 1.1 thorpej 221 1.1 thorpej static u_long 222 1.1 thorpej atobytes(const char *s) 223 1.1 thorpej { 224 1.1 thorpej u_long bytes; 225 1.1 thorpej char *cp; 226 1.1 thorpej 227 1.1 thorpej bytes = strtoul(s, &cp, 0); 228 1.1 thorpej if (cp != NULL) { 229 1.1 thorpej if (*cp == 'K' || *cp == 'k') 230 1.1 thorpej bytes *= 1024; 231 1.1 thorpej else if (*cp == 'M' || *cp == 'm') 232 1.1 thorpej bytes *= 1024 * 1024; 233 1.1 thorpej else if (*cp == 'G' || *cp == 'g') 234 1.1 thorpej bytes *= 1024 * 1024 * 1024; 235 1.1 thorpej } 236 1.1 thorpej return (bytes); 237 1.1 thorpej } 238 1.1 thorpej 239 1.1 thorpej /* 240 1.5 andvar * use heuristics to determine the bucket size 241 1.1 thorpej */ 242 1.1 thorpej static u_int 243 1.1 thorpej size_bucket(const char *ifname, const u_int rate) 244 1.1 thorpej { 245 1.1 thorpej u_int size, mtu; 246 1.1 thorpej 247 1.1 thorpej mtu = get_ifmtu(ifname); 248 1.1 thorpej if (mtu > 1500) 249 1.1 thorpej mtu = 1500; /* assume that the path mtu is still 1500 */ 250 1.1 thorpej 251 1.1 thorpej if (rate <= 1*1000*1000) 252 1.1 thorpej size = 1; 253 1.1 thorpej else if (rate <= 10*1000*1000) 254 1.1 thorpej size = 4; 255 1.1 thorpej else if (rate <= 200*1000*1000) 256 1.1 thorpej size = 8; 257 1.1 thorpej else 258 1.1 thorpej size = 24; 259 1.1 thorpej 260 1.1 thorpej size = size * mtu; 261 1.1 thorpej return (size); 262 1.1 thorpej } 263 1.1 thorpej 264 1.1 thorpej /* 265 1.1 thorpej * compute the bucket size to be required to fill the rate 266 1.1 thorpej * even when the rate is controlled only by the kernel timer. 267 1.1 thorpej */ 268 1.1 thorpej static u_int 269 1.1 thorpej autosize_bucket(const char *ifname, const u_int rate) 270 1.1 thorpej { 271 1.1 thorpej u_int size, freq, mtu; 272 1.1 thorpej 273 1.1 thorpej mtu = get_ifmtu(ifname); 274 1.1 thorpej freq = get_clockfreq(); 275 1.1 thorpej size = rate / 8 / freq; 276 1.1 thorpej if (size < mtu) 277 1.1 thorpej size = mtu; 278 1.1 thorpej return (size); 279 1.1 thorpej } 280 1.1 thorpej 281 1.1 thorpej static int 282 1.1 thorpej get_clockfreq(void) 283 1.1 thorpej { 284 1.1 thorpej struct clockinfo clkinfo; 285 1.1 thorpej int mib[2]; 286 1.1 thorpej size_t len; 287 1.1 thorpej 288 1.1 thorpej clkinfo.hz = 100; /* default Hz */ 289 1.1 thorpej 290 1.1 thorpej mib[0] = CTL_KERN; 291 1.1 thorpej mib[1] = KERN_CLOCKRATE; 292 1.1 thorpej len = sizeof(struct clockinfo); 293 1.1 thorpej if (sysctl(mib, 2, &clkinfo, &len, NULL, 0) == -1) 294 1.1 thorpej warnx("can't get clockrate via sysctl! use %dHz", clkinfo.hz); 295 1.1 thorpej return (clkinfo.hz); 296 1.1 thorpej } 297 1.1 thorpej 298 1.1 thorpej static int 299 1.1 thorpej get_ifmtu(const char *ifname) 300 1.1 thorpej { 301 1.1 thorpej int s, mtu; 302 1.1 thorpej struct ifreq ifr; 303 1.1 thorpej #ifdef __OpenBSD__ 304 1.1 thorpej struct if_data ifdata; 305 1.1 thorpej #endif 306 1.1 thorpej 307 1.1 thorpej mtu = 512; /* default MTU */ 308 1.1 thorpej 309 1.1 thorpej if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 310 1.1 thorpej return (mtu); 311 1.1 thorpej strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 312 1.1 thorpej #ifdef __OpenBSD__ 313 1.1 thorpej ifr.ifr_data = (caddr_t)&ifdata; 314 1.1 thorpej if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0) 315 1.1 thorpej mtu = ifdata.ifi_mtu; 316 1.1 thorpej #else 317 1.1 thorpej if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) 318 1.1 thorpej mtu = ifr.ifr_mtu; 319 1.1 thorpej #endif 320 1.1 thorpej close(s); 321 1.1 thorpej return (mtu); 322 1.1 thorpej } 323