1 1.13 ozaki /* $NetBSD: qop_cbq.c,v 1.13 2024/12/24 08:35:28 ozaki-r Exp $ */ 2 1.6 itojun /* $KAME: qop_cbq.c,v 1.7 2002/05/31 06:03:35 kjc Exp $ */ 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved. 5 1.1 thorpej * 6 1.1 thorpej * Redistribution and use in source and binary forms, with or without 7 1.1 thorpej * modification, are permitted provided that the following conditions 8 1.1 thorpej * are met: 9 1.1 thorpej * 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 * 13 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 15 1.1 thorpej * documentation and/or other materials provided with the distribution. 16 1.1 thorpej * 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed by the SMCC Technology 20 1.1 thorpej * Development Group at Sun Microsystems, Inc. 21 1.1 thorpej * 22 1.1 thorpej * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or 23 1.1 thorpej * promote products derived from this software without specific prior 24 1.1 thorpej * written permission. 25 1.1 thorpej * 26 1.1 thorpej * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE 27 1.1 thorpej * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is 28 1.1 thorpej * provided "as is" without express or implied warranty of any kind. 29 1.1 thorpej * 30 1.1 thorpej * These notices must be retained in any copies of any part of this software. 31 1.1 thorpej */ 32 1.1 thorpej 33 1.1 thorpej #include <sys/param.h> 34 1.1 thorpej #include <sys/socket.h> 35 1.1 thorpej #include <sys/sockio.h> 36 1.1 thorpej #include <sys/ioctl.h> 37 1.1 thorpej #include <sys/fcntl.h> 38 1.1 thorpej #include <net/if.h> 39 1.1 thorpej #include <netinet/in.h> 40 1.1 thorpej #include <arpa/inet.h> 41 1.1 thorpej 42 1.1 thorpej #include <stdio.h> 43 1.1 thorpej #include <stdlib.h> 44 1.1 thorpej #include <unistd.h> 45 1.1 thorpej #include <stddef.h> 46 1.1 thorpej #include <string.h> 47 1.1 thorpej #include <ctype.h> 48 1.1 thorpej #include <errno.h> 49 1.1 thorpej #include <syslog.h> 50 1.1 thorpej #include <netdb.h> 51 1.1 thorpej #include <math.h> 52 1.1 thorpej 53 1.1 thorpej #include <altq/altq.h> 54 1.1 thorpej #include <altq/altq_cbq.h> 55 1.1 thorpej #include "altq_qop.h" 56 1.1 thorpej #include "qop_cbq.h" 57 1.1 thorpej 58 1.2 itojun static int qcmd_cbq_add_ctl_filters(const char *, const char *); 59 1.1 thorpej 60 1.2 itojun static int qop_cbq_enable_hook(struct ifinfo *); 61 1.2 itojun static int qop_cbq_delete_class_hook(struct classinfo *); 62 1.1 thorpej 63 1.2 itojun static int cbq_class_spec(struct ifinfo *, u_long, u_long, u_int, int, 64 1.13 ozaki uint64_t, u_int, u_int, u_int, u_int, 65 1.2 itojun u_int, cbq_class_spec_t *); 66 1.1 thorpej 67 1.2 itojun static int cbq_attach(struct ifinfo *); 68 1.2 itojun static int cbq_detach(struct ifinfo *); 69 1.2 itojun static int cbq_clear(struct ifinfo *); 70 1.2 itojun static int cbq_enable(struct ifinfo *); 71 1.2 itojun static int cbq_disable(struct ifinfo *); 72 1.2 itojun static int cbq_add_class(struct classinfo *); 73 1.2 itojun static int cbq_modify_class(struct classinfo *, void *); 74 1.2 itojun static int cbq_delete_class(struct classinfo *); 75 1.2 itojun static int cbq_add_filter(struct fltrinfo *); 76 1.2 itojun static int cbq_delete_filter(struct fltrinfo *); 77 1.1 thorpej 78 1.1 thorpej #define CTL_PBANDWIDTH 2 79 1.1 thorpej #define NS_PER_MS (1000000.0) 80 1.1 thorpej #define NS_PER_SEC (NS_PER_MS*1000.0) 81 1.12 ozaki #define PS_PER_MS (1000000000.0) 82 1.12 ozaki #define PS_PER_SEC (PS_PER_MS*1000.0) 83 1.1 thorpej #define RM_FILTER_GAIN 5 84 1.1 thorpej 85 1.12 ozaki #define PSEC_TO_USEC(ps) ((ps) / 1000.0 / 1000.0) 86 1.12 ozaki 87 1.1 thorpej #define CBQ_DEVICE "/dev/altq/cbq" 88 1.1 thorpej 89 1.1 thorpej static int cbq_fd = -1; 90 1.1 thorpej static int cbq_refcount = 0; 91 1.1 thorpej 92 1.1 thorpej static struct qdisc_ops cbq_qdisc = { 93 1.1 thorpej ALTQT_CBQ, 94 1.1 thorpej "cbq", 95 1.1 thorpej cbq_attach, 96 1.1 thorpej cbq_detach, 97 1.1 thorpej cbq_clear, 98 1.1 thorpej cbq_enable, 99 1.1 thorpej cbq_disable, 100 1.1 thorpej cbq_add_class, 101 1.1 thorpej cbq_modify_class, 102 1.1 thorpej cbq_delete_class, 103 1.1 thorpej cbq_add_filter, 104 1.1 thorpej cbq_delete_filter, 105 1.1 thorpej }; 106 1.1 thorpej 107 1.1 thorpej #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) 108 1.1 thorpej 109 1.1 thorpej /* 110 1.1 thorpej * parser interface 111 1.1 thorpej */ 112 1.1 thorpej int 113 1.1 thorpej cbq_interface_parser(const char *ifname, int argc, char **argv) 114 1.1 thorpej { 115 1.13 ozaki uint64_t bandwidth = 100000000; /* 100Mbps */ 116 1.1 thorpej u_int tbrsize = 0; 117 1.1 thorpej u_int is_efficient = 0; 118 1.1 thorpej u_int is_wrr = 1; /* weighted round-robin is default */ 119 1.11 ozaki bool no_control = false; 120 1.11 ozaki bool no_tbr = false; 121 1.1 thorpej 122 1.1 thorpej /* 123 1.1 thorpej * process options 124 1.1 thorpej */ 125 1.1 thorpej while (argc > 0) { 126 1.1 thorpej if (EQUAL(*argv, "bandwidth")) { 127 1.1 thorpej argc--; argv++; 128 1.1 thorpej if (argc > 0) 129 1.1 thorpej bandwidth = atobps(*argv); 130 1.1 thorpej } else if (EQUAL(*argv, "tbrsize")) { 131 1.1 thorpej argc--; argv++; 132 1.1 thorpej if (argc > 0) 133 1.1 thorpej tbrsize = atobytes(*argv); 134 1.1 thorpej } else if (EQUAL(*argv, "efficient")) { 135 1.1 thorpej is_efficient = 1; 136 1.1 thorpej } else if (EQUAL(*argv, "cbq")) { 137 1.1 thorpej /* just skip */ 138 1.1 thorpej } else if (EQUAL(*argv, "cbq-wrr")) { 139 1.1 thorpej is_wrr = 1; 140 1.1 thorpej } else if (EQUAL(*argv, "cbq-prr")) { 141 1.1 thorpej is_wrr = 0; 142 1.11 ozaki } else if (EQUAL(*argv, "no-tbr")) { 143 1.11 ozaki no_tbr = true; 144 1.11 ozaki } else if (EQUAL(*argv, "no-control")) { 145 1.11 ozaki no_control = true; 146 1.1 thorpej } else { 147 1.5 itojun LOG(LOG_ERR, 0, "Unknown keyword '%s'", *argv); 148 1.1 thorpej return (0); 149 1.1 thorpej } 150 1.1 thorpej argc--; argv++; 151 1.1 thorpej } 152 1.1 thorpej 153 1.11 ozaki if (!no_tbr) { 154 1.11 ozaki if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0) 155 1.11 ozaki return (0); 156 1.11 ozaki } 157 1.1 thorpej 158 1.1 thorpej if (qcmd_cbq_add_if(ifname, bandwidth, 159 1.11 ozaki is_wrr, is_efficient, no_control) != 0) 160 1.1 thorpej return (0); 161 1.11 ozaki 162 1.1 thorpej return (1); 163 1.1 thorpej } 164 1.1 thorpej 165 1.1 thorpej int 166 1.1 thorpej cbq_class_parser(const char *ifname, const char *class_name, 167 1.1 thorpej const char *parent_name, int argc, char **argv) 168 1.1 thorpej { 169 1.1 thorpej const char *borrow = NULL; 170 1.1 thorpej u_int pri = 1; 171 1.1 thorpej u_int pbandwidth = 0; 172 1.13 ozaki uint64_t bandwidth = 0; 173 1.1 thorpej u_int maxdelay = 0; /* 0 means default */ 174 1.1 thorpej u_int maxburst = 0; /* 0 means default */ 175 1.1 thorpej u_int minburst = 0; /* 0 means default */ 176 1.1 thorpej u_int av_pkt_size = 0; /* 0 means use if mtu as default */ 177 1.1 thorpej u_int max_pkt_size = 0; /* 0 means use if mtu as default */ 178 1.1 thorpej int flags = 0; 179 1.1 thorpej cbq_tos_t admission_type = CBQ_QOS_NONE; 180 1.1 thorpej int error; 181 1.1 thorpej 182 1.1 thorpej if (parent_name == NULL) 183 1.1 thorpej flags |= CBQCLF_ROOTCLASS; 184 1.1 thorpej 185 1.1 thorpej while (argc > 0) { 186 1.1 thorpej if (EQUAL(*argv, "priority")) { 187 1.1 thorpej argc--; argv++; 188 1.1 thorpej if (argc > 0) 189 1.1 thorpej pri = strtoul(*argv, NULL, 0); 190 1.1 thorpej } else if (EQUAL(*argv, "default")) { 191 1.1 thorpej flags |= CBQCLF_DEFCLASS; 192 1.1 thorpej } else if (EQUAL(*argv, "control")) { 193 1.1 thorpej flags |= CBQCLF_CTLCLASS; 194 1.1 thorpej } else if (EQUAL(*argv, "admission")) { 195 1.1 thorpej argc--; argv++; 196 1.1 thorpej if (argc > 0) { 197 1.1 thorpej if (EQUAL(*argv, "guaranteed")) 198 1.1 thorpej admission_type = CBQ_QOS_GUARANTEED; 199 1.1 thorpej else if (EQUAL(*argv, "predictive")) 200 1.1 thorpej admission_type = CBQ_QOS_PREDICTIVE; 201 1.1 thorpej else if (EQUAL(*argv, "cntlload")) 202 1.1 thorpej admission_type = CBQ_QOS_CNTR_LOAD; 203 1.1 thorpej else if (EQUAL(*argv, "cntldelay")) 204 1.1 thorpej admission_type = CBQ_QOS_CNTR_DELAY; 205 1.1 thorpej else if (EQUAL(*argv, "none")) 206 1.1 thorpej admission_type = CBQ_QOS_NONE; 207 1.1 thorpej else { 208 1.1 thorpej LOG(LOG_ERR, 0, 209 1.4 itojun "unknown admission type - %s, line %d", 210 1.1 thorpej *argv, line_no); 211 1.1 thorpej return (0); 212 1.1 thorpej } 213 1.1 thorpej } 214 1.1 thorpej } else if (EQUAL(*argv, "maxdelay")) { 215 1.1 thorpej argc--; argv++; 216 1.1 thorpej if (argc > 0) 217 1.1 thorpej maxdelay = strtoul(*argv, NULL, 0); 218 1.1 thorpej } else if (EQUAL(*argv, "borrow")) { 219 1.1 thorpej borrow = parent_name; 220 1.1 thorpej #if 1 221 1.1 thorpej /* support old style "borrow [parent]" */ 222 1.1 thorpej if (argc > 1 && 223 1.1 thorpej EQUAL(*(argv + 1), parent_name)) { 224 1.1 thorpej /* old style, skip borrow_name */ 225 1.1 thorpej argc--; argv++; 226 1.1 thorpej } 227 1.1 thorpej #endif 228 1.1 thorpej } else if (EQUAL(*argv, "pbandwidth")) { 229 1.1 thorpej argc--; argv++; 230 1.1 thorpej if (argc > 0) 231 1.1 thorpej pbandwidth = strtoul(*argv, NULL, 0); 232 1.1 thorpej if (pbandwidth > 100) { 233 1.1 thorpej LOG(LOG_ERR, 0, 234 1.4 itojun "bad pbandwidth %d for %s!", 235 1.1 thorpej pbandwidth, class_name); 236 1.1 thorpej return (0); 237 1.1 thorpej } 238 1.1 thorpej } else if (EQUAL(*argv, "exactbandwidth")) { 239 1.1 thorpej argc--; argv++; 240 1.1 thorpej if (argc > 0) 241 1.1 thorpej bandwidth = atobps(*argv); 242 1.1 thorpej } else if (EQUAL(*argv, "maxburst")) { 243 1.1 thorpej argc--; argv++; 244 1.1 thorpej if (argc > 0) 245 1.1 thorpej maxburst = strtoul(*argv, NULL, 0); 246 1.1 thorpej } else if (EQUAL(*argv, "minburst")) { 247 1.1 thorpej argc--; argv++; 248 1.1 thorpej if (argc > 0) 249 1.1 thorpej minburst = strtoul(*argv, NULL, 0); 250 1.1 thorpej } else if (EQUAL(*argv, "packetsize")) { 251 1.1 thorpej argc--; argv++; 252 1.1 thorpej if (argc > 0) 253 1.1 thorpej av_pkt_size = atobytes(*argv); 254 1.1 thorpej } else if (EQUAL(*argv, "maxpacketsize")) { 255 1.1 thorpej argc--; argv++; 256 1.1 thorpej if (argc > 0) 257 1.1 thorpej max_pkt_size = atobytes(*argv); 258 1.1 thorpej } else if (EQUAL(*argv, "red")) { 259 1.1 thorpej flags |= CBQCLF_RED; 260 1.1 thorpej } else if (EQUAL(*argv, "ecn")) { 261 1.1 thorpej flags |= CBQCLF_ECN; 262 1.1 thorpej } else if (EQUAL(*argv, "flowvalve")) { 263 1.1 thorpej flags |= CBQCLF_FLOWVALVE; 264 1.1 thorpej } else if (EQUAL(*argv, "rio")) { 265 1.1 thorpej flags |= CBQCLF_RIO; 266 1.1 thorpej } else if (EQUAL(*argv, "cleardscp")) { 267 1.1 thorpej flags |= CBQCLF_CLEARDSCP; 268 1.1 thorpej } else { 269 1.1 thorpej LOG(LOG_ERR, 0, 270 1.4 itojun "Unknown keyword '%s' in %s, line %d", 271 1.1 thorpej *argv, altqconfigfile, line_no); 272 1.1 thorpej return (0); 273 1.1 thorpej } 274 1.1 thorpej 275 1.1 thorpej argc--; argv++; 276 1.1 thorpej } 277 1.1 thorpej 278 1.1 thorpej if ((flags & (CBQCLF_RED|CBQCLF_RIO)) == (CBQCLF_RED|CBQCLF_RIO)) { 279 1.1 thorpej LOG(LOG_ERR, 0, 280 1.4 itojun "both red and rio defined on interface '%s'", 281 1.1 thorpej ifname); 282 1.1 thorpej return (0); 283 1.1 thorpej } 284 1.1 thorpej if ((flags & (CBQCLF_ECN|CBQCLF_FLOWVALVE)) 285 1.1 thorpej && (flags & (CBQCLF_RED|CBQCLF_RIO)) == 0) 286 1.1 thorpej flags |= CBQCLF_RED; 287 1.1 thorpej 288 1.1 thorpej if (strcmp("ctl_class", class_name) == 0) 289 1.1 thorpej flags |= CBQCLF_CTLCLASS; 290 1.1 thorpej 291 1.1 thorpej if (bandwidth == 0 && pbandwidth != 0) { 292 1.1 thorpej struct ifinfo *ifinfo; 293 1.1 thorpej 294 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) != NULL) 295 1.1 thorpej bandwidth = ifinfo->bandwidth / 100 * pbandwidth; 296 1.1 thorpej } 297 1.1 thorpej 298 1.1 thorpej error = qcmd_cbq_add_class(ifname, class_name, parent_name, borrow, 299 1.1 thorpej pri, bandwidth, 300 1.1 thorpej maxdelay, maxburst, minburst, 301 1.1 thorpej av_pkt_size, max_pkt_size, 302 1.1 thorpej admission_type, flags); 303 1.1 thorpej if (error) 304 1.1 thorpej return (0); 305 1.1 thorpej return (1); 306 1.1 thorpej } 307 1.1 thorpej 308 1.1 thorpej /* 309 1.1 thorpej * qcmd api 310 1.1 thorpej */ 311 1.1 thorpej int 312 1.13 ozaki qcmd_cbq_add_if(const char *ifname, uint64_t bandwidth, int is_wrr, int efficient, 313 1.11 ozaki bool no_control) 314 1.1 thorpej { 315 1.1 thorpej int error; 316 1.1 thorpej 317 1.11 ozaki error = qop_cbq_add_if(NULL, ifname, bandwidth, is_wrr, efficient, 318 1.11 ozaki no_control); 319 1.1 thorpej if (error != 0) 320 1.4 itojun LOG(LOG_ERR, errno, "%s: can't add cbq on interface '%s'", 321 1.1 thorpej qoperror(error), ifname); 322 1.1 thorpej return (error); 323 1.1 thorpej } 324 1.1 thorpej 325 1.1 thorpej int 326 1.1 thorpej qcmd_cbq_add_class(const char *ifname, const char *class_name, 327 1.1 thorpej const char *parent_name, const char *borrow_name, 328 1.13 ozaki u_int pri, uint64_t bandwidth, 329 1.1 thorpej u_int maxdelay, u_int maxburst, u_int minburst, 330 1.1 thorpej u_int av_pkt_size, u_int max_pkt_size, 331 1.1 thorpej int admission_type, int flags) 332 1.1 thorpej { 333 1.1 thorpej struct ifinfo *ifinfo; 334 1.1 thorpej struct cbq_ifinfo *cbq_ifinfo; 335 1.1 thorpej struct classinfo *parent = NULL, *borrow = NULL; 336 1.13 ozaki uint64_t ctl_bandwidth = 0; 337 1.1 thorpej int error = 0; 338 1.1 thorpej 339 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 340 1.1 thorpej error = QOPERR_BADIF; 341 1.1 thorpej cbq_ifinfo = ifinfo->private; 342 1.1 thorpej 343 1.1 thorpej if (error == 0 && parent_name != NULL && 344 1.1 thorpej (parent = clname2clinfo(ifinfo, parent_name)) == NULL) 345 1.1 thorpej error = QOPERR_BADCLASS; 346 1.1 thorpej 347 1.1 thorpej if (error == 0 && borrow_name != NULL && 348 1.1 thorpej (borrow = clname2clinfo(ifinfo, borrow_name)) == NULL) 349 1.1 thorpej error = QOPERR_BADCLASS; 350 1.1 thorpej 351 1.11 ozaki if (flags & CBQCLF_DEFCLASS && !cbq_ifinfo->no_control) { 352 1.1 thorpej /* 353 1.1 thorpej * if this is a default class and no ctl_class is defined, 354 1.1 thorpej * we will create a ctl_class. 355 1.1 thorpej */ 356 1.1 thorpej if (cbq_ifinfo->ctl_class == NULL) { 357 1.1 thorpej /* reserve bandwidth for ctl_class */ 358 1.1 thorpej ctl_bandwidth = 359 1.1 thorpej ifinfo->bandwidth / 100 * CTL_PBANDWIDTH; 360 1.6 itojun if (bandwidth <= ctl_bandwidth) 361 1.6 itojun LOG(LOG_ERR, 0, 362 1.6 itojun "bandwidth for default class too small!"); 363 1.1 thorpej bandwidth -= ctl_bandwidth; 364 1.1 thorpej } 365 1.1 thorpej } 366 1.1 thorpej 367 1.1 thorpej if (error == 0) 368 1.1 thorpej error = qop_cbq_add_class(NULL, class_name, ifinfo, parent, 369 1.1 thorpej borrow, pri, bandwidth, 370 1.1 thorpej maxdelay, maxburst, minburst, 371 1.1 thorpej av_pkt_size, max_pkt_size, 372 1.1 thorpej admission_type, flags); 373 1.1 thorpej if (error != 0) 374 1.1 thorpej LOG(LOG_ERR, errno, 375 1.4 itojun "cbq: %s: can't add class '%s' on interface '%s'", 376 1.1 thorpej qoperror(error), class_name, ifname); 377 1.1 thorpej 378 1.1 thorpej if (ctl_bandwidth != 0) { 379 1.1 thorpej /* 380 1.1 thorpej * If were adding the default traffic class and 381 1.1 thorpej * no ctl_class is defined, also add the ctl traffic class. 382 1.1 thorpej * This is for RSVP and IGMP packets. 383 1.1 thorpej */ 384 1.1 thorpej if (qcmd_cbq_add_class(ifname, "ctl_class", parent_name, 385 1.1 thorpej borrow_name, 6, ctl_bandwidth, 386 1.1 thorpej maxdelay, maxburst, minburst, av_pkt_size, 387 1.1 thorpej max_pkt_size, admission_type, CBQCLF_CTLCLASS) != 0) { 388 1.1 thorpej LOG(LOG_ERR, errno, "can't create ctl_class!"); 389 1.1 thorpej return (QOPERR_CLASS); 390 1.1 thorpej } 391 1.1 thorpej } 392 1.1 thorpej 393 1.1 thorpej /* 394 1.1 thorpej * if this is a ctl class, add the default filters for backward 395 1.1 thorpej * compatibility 396 1.1 thorpej */ 397 1.1 thorpej if (flags & CBQCLF_CTLCLASS) 398 1.1 thorpej qcmd_cbq_add_ctl_filters(ifname, class_name); 399 1.1 thorpej 400 1.1 thorpej return (error); 401 1.1 thorpej } 402 1.1 thorpej 403 1.1 thorpej int 404 1.1 thorpej qcmd_cbq_modify_class(const char *ifname, const char *class_name, 405 1.13 ozaki u_int pri, uint64_t bandwidth, 406 1.1 thorpej u_int maxdelay, u_int maxburst, u_int minburst, 407 1.1 thorpej u_int av_pkt_size, u_int max_pkt_size, int flags) 408 1.1 thorpej { 409 1.1 thorpej struct ifinfo *ifinfo; 410 1.1 thorpej struct classinfo *clinfo; 411 1.1 thorpej 412 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 413 1.1 thorpej return (QOPERR_BADIF); 414 1.1 thorpej 415 1.1 thorpej if ((clinfo = clname2clinfo(ifinfo, class_name)) == NULL) 416 1.1 thorpej return (QOPERR_BADCLASS); 417 1.1 thorpej 418 1.1 thorpej return qop_cbq_modify_class(clinfo, pri, bandwidth, 419 1.1 thorpej maxdelay, maxburst, minburst, 420 1.1 thorpej av_pkt_size, max_pkt_size, flags); 421 1.1 thorpej } 422 1.1 thorpej 423 1.1 thorpej /* 424 1.1 thorpej * add the default filters for ctl_class (for backward compatibility). 425 1.1 thorpej */ 426 1.1 thorpej #ifndef IPPROTO_RSVP 427 1.1 thorpej #define IPPROTO_RSVP 46 428 1.1 thorpej #endif 429 1.1 thorpej 430 1.1 thorpej static int 431 1.1 thorpej qcmd_cbq_add_ctl_filters(const char *ifname, const char *clname) 432 1.1 thorpej { 433 1.1 thorpej struct flow_filter sfilt; 434 1.1 thorpej u_int8_t ctl_protos[3] = {IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_RSVP}; 435 1.1 thorpej #ifdef INET6 436 1.1 thorpej struct flow_filter6 sfilt6; 437 1.1 thorpej u_int8_t ctl6_protos[3] = {IPPROTO_ICMPV6, IPPROTO_IGMP, IPPROTO_RSVP}; 438 1.1 thorpej #endif 439 1.8 lukem int error; 440 1.8 lukem size_t i; 441 1.1 thorpej 442 1.8 lukem for (i = 0; i < sizeof(ctl_protos); i++) { 443 1.1 thorpej memset(&sfilt, 0, sizeof(sfilt)); 444 1.1 thorpej sfilt.ff_flow.fi_family = AF_INET; 445 1.1 thorpej sfilt.ff_flow.fi_proto = ctl_protos[i]; 446 1.1 thorpej 447 1.1 thorpej filter_dontwarn = 1; /* XXX */ 448 1.1 thorpej error = qcmd_add_filter(ifname, clname, NULL, &sfilt); 449 1.1 thorpej filter_dontwarn = 0; /* XXX */ 450 1.1 thorpej if (error) { 451 1.1 thorpej LOG(LOG_ERR, 0, 452 1.4 itojun "can't add ctl class filter on interface '%s'", 453 1.1 thorpej ifname); 454 1.1 thorpej return (error); 455 1.1 thorpej } 456 1.1 thorpej } 457 1.1 thorpej 458 1.1 thorpej #ifdef INET6 459 1.1 thorpej for (i = 0; i < sizeof(ctl6_protos); i++) { 460 1.1 thorpej memset(&sfilt6, 0, sizeof(sfilt6)); 461 1.1 thorpej sfilt6.ff_flow6.fi6_family = AF_INET6; 462 1.1 thorpej sfilt6.ff_flow6.fi6_proto = ctl6_protos[i]; 463 1.1 thorpej 464 1.1 thorpej error = qcmd_add_filter(ifname, clname, NULL, 465 1.1 thorpej (struct flow_filter *)&sfilt6); 466 1.1 thorpej if (error) { 467 1.1 thorpej LOG(LOG_WARNING, 0, 468 1.4 itojun "can't add ctl class IPv6 filter on interface '%s'", 469 1.1 thorpej ifname); 470 1.1 thorpej return (error); 471 1.1 thorpej } 472 1.1 thorpej } 473 1.1 thorpej #endif 474 1.1 thorpej return (0); 475 1.1 thorpej } 476 1.1 thorpej 477 1.1 thorpej /* 478 1.1 thorpej * qop api 479 1.1 thorpej */ 480 1.1 thorpej int 481 1.1 thorpej qop_cbq_add_if(struct ifinfo **rp, const char *ifname, 482 1.13 ozaki uint64_t bandwidth, int is_wrr, int efficient, bool no_control) 483 1.1 thorpej { 484 1.1 thorpej struct ifinfo *ifinfo = NULL; 485 1.1 thorpej struct cbq_ifinfo *cbq_ifinfo = NULL; 486 1.1 thorpej int error; 487 1.1 thorpej 488 1.1 thorpej if ((cbq_ifinfo = calloc(1, sizeof(*cbq_ifinfo))) == NULL) 489 1.1 thorpej return (QOPERR_NOMEM); 490 1.1 thorpej 491 1.12 ozaki cbq_ifinfo->psPerByte = 492 1.12 ozaki (1.0 / (double)bandwidth) * PS_PER_SEC * 8; 493 1.1 thorpej cbq_ifinfo->is_wrr = is_wrr; 494 1.1 thorpej cbq_ifinfo->is_efficient = efficient; 495 1.11 ozaki cbq_ifinfo->no_control = no_control; 496 1.1 thorpej 497 1.1 thorpej error = qop_add_if(&ifinfo, ifname, bandwidth, 498 1.1 thorpej &cbq_qdisc, cbq_ifinfo); 499 1.1 thorpej if (error != 0) 500 1.1 thorpej goto err_ret; 501 1.1 thorpej 502 1.1 thorpej /* set enable hook */ 503 1.1 thorpej ifinfo->enable_hook = qop_cbq_enable_hook; 504 1.1 thorpej 505 1.1 thorpej if (rp != NULL) 506 1.1 thorpej *rp = ifinfo; 507 1.1 thorpej return (0); 508 1.1 thorpej 509 1.1 thorpej err_ret: 510 1.1 thorpej if (cbq_ifinfo != NULL) { 511 1.1 thorpej free(cbq_ifinfo); 512 1.1 thorpej if (ifinfo != NULL) 513 1.1 thorpej ifinfo->private = NULL; 514 1.1 thorpej } 515 1.1 thorpej return (error); 516 1.1 thorpej } 517 1.1 thorpej 518 1.1 thorpej #define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0)) 519 1.1 thorpej 520 1.1 thorpej int 521 1.1 thorpej qop_cbq_add_class(struct classinfo **rp, const char *class_name, 522 1.1 thorpej struct ifinfo *ifinfo, struct classinfo *parent, 523 1.13 ozaki struct classinfo *borrow, u_int pri, uint64_t bandwidth, 524 1.1 thorpej u_int maxdelay, u_int maxburst, u_int minburst, 525 1.1 thorpej u_int av_pkt_size, u_int max_pkt_size, 526 1.1 thorpej int admission_type, int flags) 527 1.1 thorpej { 528 1.1 thorpej struct classinfo *clinfo; 529 1.1 thorpej struct cbq_ifinfo *cbq_ifinfo; 530 1.1 thorpej struct cbq_classinfo *cbq_clinfo, *parent_clinfo; 531 1.1 thorpej u_int parent_handle, borrow_handle; 532 1.1 thorpej int error; 533 1.1 thorpej 534 1.1 thorpej cbq_ifinfo = ifinfo->private; 535 1.1 thorpej 536 1.1 thorpej if (parent == NULL) { 537 1.1 thorpej if (cbq_ifinfo->root_class != NULL) 538 1.1 thorpej return (QOPERR_CLASS_INVAL); 539 1.1 thorpej flags |= CBQCLF_ROOTCLASS; 540 1.1 thorpej } 541 1.1 thorpej if ((flags & CBQCLF_DEFCLASS) && cbq_ifinfo->default_class != NULL) 542 1.1 thorpej return (QOPERR_CLASS_INVAL); 543 1.1 thorpej if ((flags & CBQCLF_CTLCLASS) && cbq_ifinfo->ctl_class != NULL) 544 1.1 thorpej return (QOPERR_CLASS_INVAL); 545 1.1 thorpej 546 1.1 thorpej /* admission control */ 547 1.1 thorpej if (parent != NULL) { 548 1.1 thorpej parent_clinfo = parent->private; 549 1.1 thorpej if (bandwidth > 550 1.1 thorpej parent_clinfo->bandwidth - parent_clinfo->allocated) { 551 1.1 thorpej #ifdef ALLOW_OVERCOMMIT 552 1.1 thorpej LOG(LOG_WARNING, 0, 553 1.4 itojun "bandwidth overcommitted %uK requested but only %dK available (%uK already allocated)", 554 1.1 thorpej bandwidth / 1000, 555 1.1 thorpej ((int)parent_clinfo->bandwidth - 556 1.1 thorpej parent_clinfo->allocated) / 1000, 557 1.1 thorpej parent_clinfo->allocated / 1000); 558 1.1 thorpej #else /* !ALLOW_OVERCOMMIT */ 559 1.1 thorpej LOG(LOG_ERR, 0, 560 1.4 itojun "cbq admission failed! %uK requested but only %uK available (%uK already allocated)", 561 1.1 thorpej bandwidth / 1000, 562 1.1 thorpej (parent_clinfo->bandwidth - 563 1.1 thorpej parent_clinfo->allocated) / 1000, 564 1.1 thorpej parent_clinfo->allocated / 1000); 565 1.1 thorpej return (QOPERR_ADMISSION_NOBW); 566 1.1 thorpej #endif /* !ALLOW_OVERCOMMIT */ 567 1.1 thorpej } 568 1.1 thorpej } 569 1.1 thorpej 570 1.1 thorpej if ((cbq_clinfo = calloc(1, sizeof(*cbq_clinfo))) == NULL) 571 1.1 thorpej return (QOPERR_NOMEM); 572 1.1 thorpej 573 1.1 thorpej cbq_clinfo->bandwidth = bandwidth; 574 1.1 thorpej cbq_clinfo->allocated = 0; 575 1.1 thorpej 576 1.9 mbalmer /* if average packet size isn't specified, set if mtu. */ 577 1.1 thorpej if (av_pkt_size == 0) { /* use default */ 578 1.1 thorpej av_pkt_size = ifinfo->ifmtu; 579 1.1 thorpej if (av_pkt_size > MCLBYTES) /* do what TCP does */ 580 1.1 thorpej av_pkt_size &= ~MCLBYTES; 581 1.1 thorpej } else if (av_pkt_size > ifinfo->ifmtu) 582 1.1 thorpej av_pkt_size = ifinfo->ifmtu; 583 1.1 thorpej 584 1.1 thorpej if (max_pkt_size == 0) /* use default */ 585 1.1 thorpej max_pkt_size = ifinfo->ifmtu; 586 1.1 thorpej else if (max_pkt_size > ifinfo->ifmtu) 587 1.1 thorpej max_pkt_size = ifinfo->ifmtu; 588 1.1 thorpej 589 1.1 thorpej cbq_clinfo->maxdelay = maxdelay; 590 1.1 thorpej cbq_clinfo->maxburst = maxburst; 591 1.1 thorpej cbq_clinfo->minburst = minburst; 592 1.1 thorpej cbq_clinfo->av_pkt_size = av_pkt_size; 593 1.1 thorpej cbq_clinfo->max_pkt_size = max_pkt_size; 594 1.1 thorpej 595 1.1 thorpej parent_handle = parent != NULL ? parent->handle : NULL_CLASS_HANDLE; 596 1.1 thorpej borrow_handle = borrow != NULL ? borrow->handle : NULL_CLASS_HANDLE; 597 1.1 thorpej 598 1.1 thorpej if (cbq_class_spec(ifinfo, parent_handle, borrow_handle, pri, flags, 599 1.1 thorpej bandwidth, maxdelay, maxburst, minburst, 600 1.1 thorpej av_pkt_size, max_pkt_size, 601 1.1 thorpej &cbq_clinfo->class_spec) < 0) { 602 1.1 thorpej error = QOPERR_INVAL; 603 1.1 thorpej goto err_ret; 604 1.1 thorpej } 605 1.1 thorpej 606 1.1 thorpej clinfo = NULL; 607 1.1 thorpej error = qop_add_class(&clinfo, class_name, ifinfo, parent, cbq_clinfo); 608 1.1 thorpej if (error != 0) 609 1.1 thorpej goto err_ret; 610 1.1 thorpej 611 1.1 thorpej /* set delete hook */ 612 1.1 thorpej clinfo->delete_hook = qop_cbq_delete_class_hook; 613 1.1 thorpej 614 1.1 thorpej if (parent == NULL) 615 1.1 thorpej cbq_ifinfo->root_class = clinfo; 616 1.1 thorpej else { 617 1.1 thorpej parent_clinfo = parent->private; 618 1.1 thorpej parent_clinfo->allocated += bandwidth; 619 1.1 thorpej } 620 1.1 thorpej if (flags & CBQCLF_DEFCLASS) 621 1.1 thorpej cbq_ifinfo->default_class = clinfo; 622 1.1 thorpej if (flags & CBQCLF_CTLCLASS) 623 1.1 thorpej cbq_ifinfo->ctl_class = clinfo; 624 1.1 thorpej 625 1.1 thorpej switch (admission_type) { 626 1.1 thorpej case CBQ_QOS_CNTR_LOAD: 627 1.1 thorpej case CBQ_QOS_GUARANTEED: 628 1.1 thorpej case CBQ_QOS_PREDICTIVE: 629 1.1 thorpej case CBQ_QOS_CNTR_DELAY: 630 1.1 thorpej if (ifinfo->resv_class != NULL) { 631 1.1 thorpej LOG(LOG_ERR, 0, 632 1.4 itojun "%s: duplicate resv meta class", class_name); 633 1.1 thorpej return (QOPERR_CLASS); 634 1.1 thorpej } 635 1.1 thorpej ifinfo->resv_class = clinfo; 636 1.1 thorpej } 637 1.1 thorpej 638 1.1 thorpej if (rp != NULL) 639 1.1 thorpej *rp = clinfo; 640 1.1 thorpej return (0); 641 1.1 thorpej 642 1.1 thorpej err_ret: 643 1.1 thorpej if (cbq_clinfo != NULL) { 644 1.1 thorpej free(cbq_clinfo); 645 1.1 thorpej if (clinfo != NULL) 646 1.1 thorpej clinfo->private = NULL; 647 1.1 thorpej } 648 1.1 thorpej return (error); 649 1.1 thorpej } 650 1.1 thorpej 651 1.1 thorpej /* 652 1.1 thorpej * this is called from qop_delete_class() before a class is destroyed 653 1.1 thorpej * for discipline specific cleanup. 654 1.1 thorpej */ 655 1.1 thorpej static int 656 1.1 thorpej qop_cbq_delete_class_hook(struct classinfo *clinfo) 657 1.1 thorpej { 658 1.1 thorpej struct cbq_classinfo *cbq_clinfo, *parent_clinfo; 659 1.1 thorpej 660 1.1 thorpej /* cancel admission control */ 661 1.1 thorpej if (clinfo->parent != NULL) { 662 1.1 thorpej cbq_clinfo = clinfo->private; 663 1.1 thorpej parent_clinfo = clinfo->parent->private; 664 1.1 thorpej 665 1.1 thorpej parent_clinfo->allocated -= cbq_clinfo->bandwidth; 666 1.1 thorpej } 667 1.1 thorpej return (0); 668 1.1 thorpej } 669 1.1 thorpej 670 1.1 thorpej int 671 1.13 ozaki qop_cbq_modify_class(struct classinfo *clinfo, u_int pri, uint64_t bandwidth, 672 1.1 thorpej u_int maxdelay, u_int maxburst, u_int minburst, 673 1.1 thorpej u_int av_pkt_size, u_int max_pkt_size, int flags) 674 1.1 thorpej { 675 1.1 thorpej struct ifinfo *ifinfo; 676 1.1 thorpej struct cbq_classinfo *cbq_clinfo, *parent_clinfo; 677 1.1 thorpej u_int parent_handle, borrow_handle; 678 1.13 ozaki uint64_t old_bandwidth; 679 1.1 thorpej int error; 680 1.1 thorpej 681 1.1 thorpej ifinfo = clinfo->ifinfo; 682 1.1 thorpej cbq_clinfo = clinfo->private; 683 1.1 thorpej 684 1.1 thorpej /* admission control */ 685 1.1 thorpej old_bandwidth = cbq_clinfo->bandwidth; 686 1.1 thorpej if (clinfo->parent != NULL) { 687 1.1 thorpej parent_clinfo = clinfo->parent->private; 688 1.1 thorpej if (bandwidth > old_bandwidth) { 689 1.1 thorpej /* increase bandwidth */ 690 1.1 thorpej if (bandwidth - old_bandwidth > 691 1.1 thorpej parent_clinfo->bandwidth 692 1.1 thorpej - parent_clinfo->allocated) 693 1.1 thorpej return (QOPERR_ADMISSION_NOBW); 694 1.1 thorpej } else if (bandwidth < old_bandwidth) { 695 1.1 thorpej /* decrease bandwidth */ 696 1.1 thorpej if (bandwidth < cbq_clinfo->allocated) 697 1.1 thorpej return (QOPERR_ADMISSION); 698 1.1 thorpej } 699 1.1 thorpej } 700 1.1 thorpej 701 1.9 mbalmer /* if average packet size isn't specified, set if mtu. */ 702 1.1 thorpej if (av_pkt_size == 0) { /* use default */ 703 1.1 thorpej av_pkt_size = ifinfo->ifmtu; 704 1.1 thorpej if (av_pkt_size > MCLBYTES) /* do what TCP does */ 705 1.1 thorpej av_pkt_size &= ~MCLBYTES; 706 1.1 thorpej } else if (av_pkt_size > ifinfo->ifmtu) 707 1.1 thorpej av_pkt_size = ifinfo->ifmtu; 708 1.1 thorpej 709 1.1 thorpej if (max_pkt_size == 0) /* use default */ 710 1.1 thorpej max_pkt_size = ifinfo->ifmtu; 711 1.1 thorpej else if (max_pkt_size > ifinfo->ifmtu) 712 1.1 thorpej max_pkt_size = ifinfo->ifmtu; 713 1.1 thorpej 714 1.1 thorpej cbq_clinfo->maxdelay = maxdelay; 715 1.1 thorpej cbq_clinfo->maxburst = maxburst; 716 1.1 thorpej cbq_clinfo->minburst = minburst; 717 1.1 thorpej cbq_clinfo->av_pkt_size = av_pkt_size; 718 1.1 thorpej cbq_clinfo->max_pkt_size = max_pkt_size; 719 1.1 thorpej 720 1.1 thorpej parent_handle = cbq_clinfo->class_spec.parent_class_handle; 721 1.1 thorpej borrow_handle = cbq_clinfo->class_spec.borrow_class_handle; 722 1.1 thorpej 723 1.1 thorpej if (cbq_class_spec(ifinfo, parent_handle, borrow_handle, pri, flags, 724 1.1 thorpej bandwidth, maxdelay, maxburst, minburst, 725 1.1 thorpej av_pkt_size, max_pkt_size, 726 1.1 thorpej &cbq_clinfo->class_spec) < 0) { 727 1.1 thorpej return (QOPERR_INVAL); 728 1.1 thorpej } 729 1.1 thorpej 730 1.1 thorpej error = qop_modify_class(clinfo, NULL); 731 1.1 thorpej 732 1.1 thorpej if (error == 0) { 733 1.1 thorpej if (clinfo->parent != NULL) { 734 1.1 thorpej parent_clinfo = clinfo->parent->private; 735 1.1 thorpej parent_clinfo->allocated -= old_bandwidth; 736 1.1 thorpej parent_clinfo->allocated += bandwidth; 737 1.1 thorpej } 738 1.1 thorpej cbq_clinfo->bandwidth = bandwidth; 739 1.1 thorpej } 740 1.1 thorpej return (error); 741 1.1 thorpej } 742 1.1 thorpej 743 1.1 thorpej /* 744 1.1 thorpej * sanity check at enabling cbq: 745 1.1 thorpej * there must one root class and one default class for an interface 746 1.1 thorpej */ 747 1.1 thorpej static int 748 1.1 thorpej qop_cbq_enable_hook(struct ifinfo *ifinfo) 749 1.1 thorpej { 750 1.1 thorpej struct cbq_ifinfo *cbq_ifinfo; 751 1.1 thorpej 752 1.1 thorpej cbq_ifinfo = ifinfo->private; 753 1.1 thorpej if (cbq_ifinfo->root_class == NULL) { 754 1.4 itojun LOG(LOG_ERR, 0, "cbq: no root class on interface %s!", 755 1.1 thorpej ifinfo->ifname); 756 1.1 thorpej return (QOPERR_CLASS); 757 1.1 thorpej } 758 1.1 thorpej if (cbq_ifinfo->default_class == NULL) { 759 1.4 itojun LOG(LOG_ERR, 0, "cbq: no default class on interface %s!", 760 1.1 thorpej ifinfo->ifname); 761 1.1 thorpej return (QOPERR_CLASS); 762 1.1 thorpej } 763 1.1 thorpej return (0); 764 1.1 thorpej } 765 1.1 thorpej 766 1.1 thorpej static int 767 1.1 thorpej cbq_class_spec(struct ifinfo *ifinfo, u_long parent_class, 768 1.1 thorpej u_long borrow_class, u_int pri, int flags, 769 1.13 ozaki uint64_t bandwidth, u_int maxdelay, u_int maxburst, 770 1.1 thorpej u_int minburst, u_int av_pkt_size, u_int max_pkt_size, 771 1.1 thorpej cbq_class_spec_t *cl_spec) 772 1.1 thorpej { 773 1.1 thorpej struct cbq_ifinfo *cbq_ifinfo = ifinfo->private; 774 1.1 thorpej double maxq, maxidle_s, maxidle, minidle, 775 1.12 ozaki lofftime, psPerByte, ptime, cptime; 776 1.1 thorpej double z = (double)(1 << RM_FILTER_GAIN); 777 1.1 thorpej double g = (1.0 - 1.0 / z); 778 1.1 thorpej double f; 779 1.1 thorpej double gton; 780 1.1 thorpej double gtom; 781 1.1 thorpej 782 1.1 thorpej /* Compute other class parameters */ 783 1.1 thorpej if (bandwidth == 0) 784 1.1 thorpej f = 0.0001; /* small enough? */ 785 1.1 thorpej else 786 1.1 thorpej f = ((double) bandwidth / (double) ifinfo->bandwidth); 787 1.1 thorpej 788 1.1 thorpej if (av_pkt_size == 0) { /* use default */ 789 1.1 thorpej av_pkt_size = ifinfo->ifmtu; 790 1.1 thorpej if (av_pkt_size > MCLBYTES) /* do what TCP does */ 791 1.1 thorpej av_pkt_size &= ~MCLBYTES; 792 1.1 thorpej } else if (av_pkt_size > ifinfo->ifmtu) 793 1.1 thorpej av_pkt_size = ifinfo->ifmtu; 794 1.1 thorpej if (max_pkt_size == 0) /* use default */ 795 1.1 thorpej max_pkt_size = ifinfo->ifmtu; 796 1.1 thorpej else if (max_pkt_size > ifinfo->ifmtu) 797 1.1 thorpej max_pkt_size = ifinfo->ifmtu; 798 1.1 thorpej 799 1.12 ozaki psPerByte = cbq_ifinfo->psPerByte / f; 800 1.12 ozaki ptime = (double) av_pkt_size * (double)cbq_ifinfo->psPerByte; 801 1.1 thorpej cptime = ptime * (1.0 - f) / f; 802 1.12 ozaki 803 1.1 thorpej if (maxburst == 0) { /* use default */ 804 1.12 ozaki if (cptime > 10.0 * PS_PER_MS) 805 1.1 thorpej maxburst = 4; 806 1.1 thorpej else 807 1.1 thorpej maxburst = 16; 808 1.1 thorpej } 809 1.1 thorpej if (minburst == 0) /* use default */ 810 1.1 thorpej minburst = 2; 811 1.1 thorpej if (minburst > maxburst) 812 1.1 thorpej minburst = maxburst; 813 1.1 thorpej 814 1.1 thorpej if (IsDebug(DEBUG_ALTQ)) { 815 1.1 thorpej int packet_time; 816 1.1 thorpej LOG(LOG_DEBUG, 0, 817 1.4 itojun "cbq_flowspec: maxburst=%d,minburst=%d,pkt_size=%d", 818 1.1 thorpej maxburst, minburst, av_pkt_size); 819 1.1 thorpej LOG(LOG_DEBUG, 0, 820 1.12 ozaki " psPerByte=%.2f ps, link's psPerByte=%.2f, f=%.3f", 821 1.12 ozaki psPerByte, cbq_ifinfo->psPerByte, f); 822 1.12 ozaki packet_time = av_pkt_size * (int)PSEC_TO_USEC(psPerByte); 823 1.1 thorpej LOG(LOG_DEBUG, 0, 824 1.1 thorpej " packet time=%d [us]\n", packet_time); 825 1.1 thorpej if (maxburst * packet_time < 20000) { 826 1.1 thorpej LOG(LOG_WARNING, 0, 827 1.4 itojun "warning: maxburst smaller than timer granularity!"); 828 1.1 thorpej LOG(LOG_WARNING, 0, 829 1.4 itojun " maxburst=%d, packet_time=%d [us]", 830 1.1 thorpej maxburst, packet_time); 831 1.1 thorpej } 832 1.1 thorpej } 833 1.1 thorpej gton = pow(g, (double)maxburst); 834 1.1 thorpej gtom = pow(g, (double)(minburst-1)); 835 1.1 thorpej maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); 836 1.1 thorpej maxidle_s = (1.0 - g); 837 1.1 thorpej if (maxidle > maxidle_s) 838 1.1 thorpej maxidle = ptime * maxidle; 839 1.1 thorpej else 840 1.1 thorpej maxidle = ptime * maxidle_s; 841 1.1 thorpej if (IsDebug(DEBUG_ALTQ)) 842 1.12 ozaki LOG(LOG_DEBUG, 0, " maxidle=%.2f us", PSEC_TO_USEC(maxidle)); 843 1.1 thorpej if (minburst) 844 1.7 xtraeme lofftime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); 845 1.1 thorpej else 846 1.7 xtraeme lofftime = cptime; 847 1.12 ozaki minidle = -((double)max_pkt_size * (double)psPerByte); 848 1.1 thorpej if (IsDebug(DEBUG_ALTQ)) 849 1.7 xtraeme LOG(LOG_DEBUG, 0, " lofftime=%.2f us minidle=%.2f us", 850 1.12 ozaki PSEC_TO_USEC(lofftime), PSEC_TO_USEC(minidle)); 851 1.1 thorpej 852 1.12 ozaki maxidle = ((maxidle * 8.0) / psPerByte) * pow(2, RM_FILTER_GAIN); 853 1.1 thorpej #if 1 /* ALTQ */ 854 1.7 xtraeme /* also scale lofftime and minidle */ 855 1.12 ozaki lofftime = (lofftime * 8.0) / psPerByte * pow(2, RM_FILTER_GAIN); 856 1.12 ozaki minidle = ((minidle * 8.0) / psPerByte) * pow(2, RM_FILTER_GAIN); 857 1.1 thorpej #endif 858 1.1 thorpej maxidle = maxidle / 1000.0; 859 1.7 xtraeme lofftime = lofftime / 1000.0; 860 1.1 thorpej minidle = minidle / 1000.0; 861 1.1 thorpej /* adjust queue size when maxdelay is specified. 862 1.1 thorpej queue size should be relative to its share */ 863 1.1 thorpej if (maxdelay == 0) { 864 1.1 thorpej if (flags & (CBQCLF_RED|CBQCLF_RIO)) 865 1.1 thorpej maxq = 60.0; 866 1.1 thorpej else 867 1.1 thorpej maxq = 30.0; 868 1.1 thorpej } else { 869 1.12 ozaki maxq = ((double) maxdelay * PS_PER_MS) / (psPerByte * av_pkt_size); 870 1.1 thorpej if (maxq < 4) { 871 1.1 thorpej LOG(LOG_WARNING, 0, 872 1.4 itojun "warning: maxq (%d) is too small. set to %d", 873 1.1 thorpej (int)maxq, 4); 874 1.1 thorpej maxq = 4; 875 1.1 thorpej } 876 1.1 thorpej } 877 1.1 thorpej if (bandwidth == 0 && borrow_class == NULL_CLASS_HANDLE) 878 1.1 thorpej /* filter out this class by setting queue size to zero */ 879 1.1 thorpej maxq = 0; 880 1.1 thorpej if (IsDebug(DEBUG_ALTQ)) { 881 1.1 thorpej if ((u_int)maxq < maxburst) 882 1.1 thorpej LOG(LOG_WARNING, 0, 883 1.4 itojun "warning: maxq (%d) is smaller than maxburst(%d)", 884 1.1 thorpej (int)maxq, maxburst); 885 1.1 thorpej else if (maxq > 100.0) 886 1.1 thorpej LOG(LOG_WARNING, 0, 887 1.1 thorpej "warning: maxq %d too large\n", (int)maxq); 888 1.4 itojun LOG(LOG_DEBUG, 0, " maxq=%d", (int)maxq); 889 1.1 thorpej } 890 1.1 thorpej 891 1.1 thorpej if (parent_class == NULL_CLASS_HANDLE) { 892 1.1 thorpej if ((flags & CBQCLF_ROOTCLASS) == 0) 893 1.1 thorpej flags |= CBQCLF_ROOTCLASS; 894 1.1 thorpej if (cbq_ifinfo->is_wrr) 895 1.1 thorpej flags |= CBQCLF_WRR; 896 1.1 thorpej if (cbq_ifinfo->is_efficient) 897 1.1 thorpej flags |= CBQCLF_EFFICIENT; 898 1.1 thorpej } 899 1.1 thorpej 900 1.1 thorpej memset((void *)cl_spec, 0, sizeof(cbq_class_spec_t)); 901 1.1 thorpej cl_spec->priority = pri; 902 1.12 ozaki cl_spec->pico_sec_per_byte = (u_long) psPerByte; 903 1.1 thorpej cl_spec->maxq = (u_int) maxq; 904 1.1 thorpej cl_spec->maxidle = (u_int) fabs(maxidle); 905 1.1 thorpej cl_spec->minidle = (int)minidle; 906 1.7 xtraeme cl_spec->offtime = (u_int) fabs(lofftime); 907 1.1 thorpej 908 1.1 thorpej cl_spec->parent_class_handle = parent_class; 909 1.1 thorpej cl_spec->borrow_class_handle = borrow_class; 910 1.1 thorpej 911 1.1 thorpej cl_spec->pktsize = av_pkt_size; 912 1.1 thorpej cl_spec->flags = flags; 913 1.1 thorpej 914 1.1 thorpej return (0); 915 1.1 thorpej } 916 1.1 thorpej 917 1.1 thorpej 918 1.1 thorpej /* 919 1.1 thorpej * system call interfaces for qdisc_ops 920 1.1 thorpej */ 921 1.1 thorpej static int 922 1.1 thorpej cbq_attach(struct ifinfo *ifinfo) 923 1.1 thorpej { 924 1.1 thorpej struct cbq_interface iface; 925 1.1 thorpej 926 1.1 thorpej if (cbq_fd < 0 && 927 1.1 thorpej (cbq_fd = open(CBQ_DEVICE, O_RDWR)) < 0 && 928 1.1 thorpej (cbq_fd = open_module(CBQ_DEVICE, O_RDWR)) < 0) { 929 1.4 itojun LOG(LOG_ERR, errno, "CBQ open"); 930 1.1 thorpej return (QOPERR_SYSCALL); 931 1.1 thorpej } 932 1.1 thorpej 933 1.1 thorpej cbq_refcount++; 934 1.1 thorpej memset(&iface, 0, sizeof(iface)); 935 1.1 thorpej strncpy(iface.cbq_ifacename, ifinfo->ifname, IFNAMSIZ); 936 1.1 thorpej 937 1.1 thorpej if (ioctl(cbq_fd, CBQ_IF_ATTACH, &iface) < 0) 938 1.1 thorpej return (QOPERR_SYSCALL); 939 1.1 thorpej return (0); 940 1.1 thorpej } 941 1.1 thorpej 942 1.1 thorpej static int 943 1.1 thorpej cbq_detach(struct ifinfo *ifinfo) 944 1.1 thorpej { 945 1.1 thorpej struct cbq_interface iface; 946 1.1 thorpej 947 1.1 thorpej memset(&iface, 0, sizeof(iface)); 948 1.1 thorpej strncpy(iface.cbq_ifacename, ifinfo->ifname, IFNAMSIZ); 949 1.1 thorpej 950 1.1 thorpej if (ioctl(cbq_fd, CBQ_IF_DETACH, &iface) < 0) 951 1.1 thorpej return (QOPERR_SYSCALL); 952 1.1 thorpej 953 1.1 thorpej if (--cbq_refcount == 0) { 954 1.1 thorpej close(cbq_fd); 955 1.1 thorpej cbq_fd = -1; 956 1.1 thorpej } 957 1.1 thorpej return (0); 958 1.1 thorpej } 959 1.1 thorpej 960 1.1 thorpej static int 961 1.1 thorpej cbq_clear(struct ifinfo *ifinfo) 962 1.1 thorpej { 963 1.1 thorpej struct cbq_interface iface; 964 1.1 thorpej 965 1.1 thorpej memset(&iface, 0, sizeof(iface)); 966 1.1 thorpej strncpy(iface.cbq_ifacename, ifinfo->ifname, IFNAMSIZ); 967 1.1 thorpej 968 1.1 thorpej if (ioctl(cbq_fd, CBQ_CLEAR_HIERARCHY, &iface) < 0) 969 1.1 thorpej return (QOPERR_SYSCALL); 970 1.1 thorpej return (0); 971 1.1 thorpej } 972 1.1 thorpej 973 1.1 thorpej static int 974 1.1 thorpej cbq_enable(struct ifinfo *ifinfo) 975 1.1 thorpej { 976 1.1 thorpej struct cbq_interface iface; 977 1.1 thorpej 978 1.1 thorpej memset(&iface, 0, sizeof(iface)); 979 1.1 thorpej strncpy(iface.cbq_ifacename, ifinfo->ifname, IFNAMSIZ); 980 1.1 thorpej 981 1.1 thorpej if (ioctl(cbq_fd, CBQ_ENABLE, &iface) < 0) 982 1.1 thorpej return (QOPERR_SYSCALL); 983 1.1 thorpej return (0); 984 1.1 thorpej } 985 1.1 thorpej 986 1.1 thorpej static int 987 1.1 thorpej cbq_disable(struct ifinfo *ifinfo) 988 1.1 thorpej { 989 1.1 thorpej struct cbq_interface iface; 990 1.1 thorpej 991 1.1 thorpej memset(&iface, 0, sizeof(iface)); 992 1.1 thorpej strncpy(iface.cbq_ifacename, ifinfo->ifname, IFNAMSIZ); 993 1.1 thorpej 994 1.1 thorpej if (ioctl(cbq_fd, CBQ_DISABLE, &iface) < 0) 995 1.1 thorpej return (QOPERR_SYSCALL); 996 1.1 thorpej return (0); 997 1.1 thorpej } 998 1.1 thorpej 999 1.1 thorpej static int 1000 1.1 thorpej cbq_add_class(struct classinfo *clinfo) 1001 1.1 thorpej { 1002 1.1 thorpej struct cbq_add_class class_add; 1003 1.1 thorpej struct cbq_classinfo *cbq_clinfo; 1004 1.1 thorpej 1005 1.1 thorpej cbq_clinfo = clinfo->private; 1006 1.1 thorpej 1007 1.1 thorpej memset(&class_add, 0, sizeof(class_add)); 1008 1.1 thorpej strncpy(class_add.cbq_iface.cbq_ifacename, 1009 1.1 thorpej clinfo->ifinfo->ifname, IFNAMSIZ); 1010 1.1 thorpej 1011 1.1 thorpej class_add.cbq_class = cbq_clinfo->class_spec; 1012 1.1 thorpej 1013 1.1 thorpej if (ioctl(cbq_fd, CBQ_ADD_CLASS, &class_add) < 0) 1014 1.1 thorpej return (QOPERR_SYSCALL); 1015 1.1 thorpej 1016 1.1 thorpej clinfo->handle = class_add.cbq_class_handle; 1017 1.1 thorpej return (0); 1018 1.1 thorpej } 1019 1.1 thorpej 1020 1.1 thorpej static int 1021 1.1 thorpej cbq_modify_class(struct classinfo *clinfo, void *arg) 1022 1.1 thorpej { 1023 1.1 thorpej struct cbq_modify_class class_mod; 1024 1.1 thorpej struct cbq_classinfo *cbq_clinfo; 1025 1.1 thorpej 1026 1.1 thorpej cbq_clinfo = clinfo->private; 1027 1.1 thorpej 1028 1.1 thorpej memset(&class_mod, 0, sizeof(class_mod)); 1029 1.1 thorpej strncpy(class_mod.cbq_iface.cbq_ifacename, 1030 1.1 thorpej clinfo->ifinfo->ifname, IFNAMSIZ); 1031 1.1 thorpej class_mod.cbq_class_handle = clinfo->handle; 1032 1.1 thorpej class_mod.cbq_class = cbq_clinfo->class_spec; 1033 1.1 thorpej 1034 1.1 thorpej if (ioctl(cbq_fd, CBQ_MODIFY_CLASS, &class_mod) < 0) 1035 1.1 thorpej return (QOPERR_SYSCALL); 1036 1.1 thorpej return (0); 1037 1.1 thorpej } 1038 1.1 thorpej 1039 1.1 thorpej static int 1040 1.1 thorpej cbq_delete_class(struct classinfo *clinfo) 1041 1.1 thorpej { 1042 1.1 thorpej struct cbq_delete_class class_delete; 1043 1.1 thorpej 1044 1.1 thorpej memset(&class_delete, 0, sizeof(class_delete)); 1045 1.1 thorpej strncpy(class_delete.cbq_iface.cbq_ifacename, 1046 1.1 thorpej clinfo->ifinfo->ifname, IFNAMSIZ); 1047 1.1 thorpej class_delete.cbq_class_handle = clinfo->handle; 1048 1.1 thorpej 1049 1.1 thorpej if (ioctl(cbq_fd, CBQ_DEL_CLASS, &class_delete) < 0) 1050 1.1 thorpej return (QOPERR_SYSCALL); 1051 1.1 thorpej return (0); 1052 1.1 thorpej } 1053 1.1 thorpej 1054 1.1 thorpej static int 1055 1.1 thorpej cbq_add_filter(struct fltrinfo *fltrinfo) 1056 1.1 thorpej { 1057 1.1 thorpej struct cbq_add_filter fltr_add; 1058 1.1 thorpej 1059 1.1 thorpej memset(&fltr_add, 0, sizeof(fltr_add)); 1060 1.1 thorpej strncpy(fltr_add.cbq_iface.cbq_ifacename, 1061 1.1 thorpej fltrinfo->clinfo->ifinfo->ifname, IFNAMSIZ); 1062 1.1 thorpej fltr_add.cbq_class_handle = fltrinfo->clinfo->handle; 1063 1.1 thorpej fltr_add.cbq_filter = fltrinfo->fltr; 1064 1.1 thorpej 1065 1.1 thorpej if (ioctl(cbq_fd, CBQ_ADD_FILTER, &fltr_add) < 0) 1066 1.1 thorpej return (QOPERR_SYSCALL); 1067 1.1 thorpej fltrinfo->handle = fltr_add.cbq_filter_handle; 1068 1.1 thorpej return (0); 1069 1.1 thorpej } 1070 1.1 thorpej 1071 1.1 thorpej static int 1072 1.1 thorpej cbq_delete_filter(struct fltrinfo *fltrinfo) 1073 1.1 thorpej { 1074 1.1 thorpej struct cbq_delete_filter fltr_del; 1075 1.1 thorpej 1076 1.1 thorpej memset(&fltr_del, 0, sizeof(fltr_del)); 1077 1.1 thorpej strncpy(fltr_del.cbq_iface.cbq_ifacename, 1078 1.1 thorpej fltrinfo->clinfo->ifinfo->ifname, IFNAMSIZ); 1079 1.1 thorpej fltr_del.cbq_filter_handle = fltrinfo->handle; 1080 1.1 thorpej 1081 1.1 thorpej if (ioctl(cbq_fd, CBQ_DEL_FILTER, &fltr_del) < 0) 1082 1.1 thorpej return (QOPERR_SYSCALL); 1083 1.1 thorpej return (0); 1084 1.1 thorpej } 1085 1.1 thorpej 1086 1.1 thorpej 1087