1 1.13 ozaki /* $NetBSD: qop.c,v 1.13 2024/12/24 08:35:28 ozaki-r Exp $ */ 2 1.5 itojun /* $KAME: qop.c,v 1.11 2001/10/26 04:57:59 kjc Exp $ */ 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (C) 1999-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/socket.h> 31 1.1 thorpej #include <sys/sockio.h> 32 1.1 thorpej #include <sys/ioctl.h> 33 1.1 thorpej #include <sys/fcntl.h> 34 1.1 thorpej #include <sys/stat.h> 35 1.1 thorpej #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 36 1.1 thorpej #include <sys/linker.h> 37 1.1 thorpej #endif 38 1.1 thorpej 39 1.1 thorpej #include <net/if.h> 40 1.1 thorpej #include <netinet/in.h> 41 1.1 thorpej #include <arpa/inet.h> 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 <err.h> 50 1.1 thorpej #include <syslog.h> 51 1.1 thorpej 52 1.1 thorpej #include <altq/altq.h> 53 1.1 thorpej #include <altq/altq_red.h> 54 1.1 thorpej #include <altq/altq_rio.h> 55 1.1 thorpej #include <altq/altq_cdnr.h> 56 1.1 thorpej #include "altq_qop.h" 57 1.1 thorpej #include "qop_cdnr.h" 58 1.1 thorpej 59 1.1 thorpej #define ALTQ_DEVICE "/dev/altq/altq" 60 1.1 thorpej #define RED_DEVICE "/dev/altq/red" 61 1.1 thorpej #define RIO_DEVICE "/dev/altq/rio" 62 1.1 thorpej #define CDNR_DEVICE "/dev/altq/cdnr" 63 1.1 thorpej 64 1.1 thorpej #ifndef LIST_HEAD_INITIALIZER 65 1.1 thorpej #define LIST_HEAD_INITIALIZER(head) { NULL } 66 1.1 thorpej #endif 67 1.1 thorpej 68 1.1 thorpej /* 69 1.1 thorpej * token bucket regulator information 70 1.1 thorpej */ 71 1.1 thorpej struct tbrinfo { 72 1.1 thorpej LIST_ENTRY(tbrinfo) link; 73 1.1 thorpej char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */ 74 1.1 thorpej struct tb_profile tb_prof, otb_prof; 75 1.1 thorpej int installed; 76 1.1 thorpej }; 77 1.1 thorpej 78 1.1 thorpej /* 79 1.1 thorpej * Static globals 80 1.1 thorpej */ 81 1.1 thorpej /* a list of configured interfaces */ 82 1.1 thorpej LIST_HEAD(qop_iflist, ifinfo) qop_iflist = LIST_HEAD_INITIALIZER(&iflist); 83 1.1 thorpej /* a list of configured token bucket regulators */ 84 1.1 thorpej LIST_HEAD(tbr_list, tbrinfo) tbr_list = LIST_HEAD_INITIALIZER(&tbr_list); 85 1.1 thorpej 86 1.1 thorpej /* 87 1.1 thorpej * internal functions 88 1.1 thorpej */ 89 1.2 itojun static int get_ifmtu(const char *); 90 1.2 itojun static void tbr_install(const char *); 91 1.2 itojun static void tbr_deinstall(const char *); 92 1.2 itojun static int add_filter_rule(struct ifinfo *, struct fltrinfo *, 93 1.2 itojun struct fltrinfo **); 94 1.2 itojun static int remove_filter_rule(struct ifinfo *, 95 1.2 itojun struct fltrinfo *); 96 1.2 itojun static int filt_check_relation(struct flow_filter *, struct flow_filter *); 97 1.2 itojun static int filt_disjoint(struct flow_filter *, struct flow_filter *); 98 1.2 itojun static int filt_subset(struct flow_filter *, struct flow_filter *); 99 1.1 thorpej 100 1.1 thorpej /* 101 1.1 thorpej * QCMD (Queue Command) API 102 1.1 thorpej */ 103 1.1 thorpej int 104 1.1 thorpej qcmd_init(void) 105 1.1 thorpej { 106 1.1 thorpej int error; 107 1.1 thorpej 108 1.1 thorpej /* read config file and execute commands */ 109 1.1 thorpej error = qcmd_config(); 110 1.4 itojun if (error != 0) 111 1.4 itojun return (error); 112 1.1 thorpej 113 1.4 itojun error = qcmd_enableall(); 114 1.1 thorpej if (error != 0) 115 1.4 itojun LOG(LOG_ERR, errno, "%s: qcmd_init failed", qoperror(error)); 116 1.1 thorpej return (error); 117 1.1 thorpej } 118 1.1 thorpej 119 1.1 thorpej int 120 1.1 thorpej qcmd_enable(const char *ifname) 121 1.1 thorpej { 122 1.1 thorpej struct ifinfo *ifinfo; 123 1.1 thorpej int error = 0; 124 1.1 thorpej 125 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 126 1.1 thorpej error = QOPERR_BADIF; 127 1.1 thorpej 128 1.1 thorpej if (error == 0) 129 1.1 thorpej error = qop_enable(ifinfo); 130 1.1 thorpej 131 1.1 thorpej if (error == 0) { 132 1.4 itojun LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)", 133 1.1 thorpej ifinfo->qdisc->qname, ifname, ifinfo->ifmtu); 134 1.1 thorpej } else 135 1.4 itojun LOG(LOG_ERR, errno, "%s: enable failed!", qoperror(error)); 136 1.1 thorpej return (error); 137 1.1 thorpej } 138 1.1 thorpej 139 1.1 thorpej int 140 1.1 thorpej qcmd_disable(const char *ifname) 141 1.1 thorpej { 142 1.1 thorpej struct ifinfo *ifinfo; 143 1.1 thorpej int error = 0; 144 1.1 thorpej 145 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 146 1.1 thorpej error = QOPERR_BADIF; 147 1.1 thorpej 148 1.1 thorpej if (error == 0) 149 1.1 thorpej error = qop_disable(ifinfo); 150 1.1 thorpej 151 1.1 thorpej if (error != 0) 152 1.4 itojun LOG(LOG_ERR, errno, "%s: disable failed!", qoperror(error)); 153 1.1 thorpej return (error); 154 1.1 thorpej } 155 1.1 thorpej 156 1.1 thorpej int 157 1.1 thorpej qcmd_enableall() 158 1.1 thorpej { 159 1.1 thorpej struct ifinfo *ifinfo; 160 1.1 thorpej int error; 161 1.1 thorpej 162 1.1 thorpej LIST_FOREACH(ifinfo, &qop_iflist, next) { 163 1.1 thorpej if ((error = qop_enable(ifinfo)) != 0) 164 1.1 thorpej return (error); 165 1.4 itojun LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)", 166 1.1 thorpej ifinfo->qdisc->qname, ifinfo->ifname, ifinfo->ifmtu); 167 1.1 thorpej } 168 1.1 thorpej return (0); 169 1.1 thorpej } 170 1.1 thorpej 171 1.1 thorpej int 172 1.1 thorpej qcmd_disableall() 173 1.1 thorpej { 174 1.1 thorpej struct ifinfo *ifinfo; 175 1.9 xtraeme int lerr, error = 0; 176 1.1 thorpej 177 1.1 thorpej LIST_FOREACH(ifinfo, &qop_iflist, next) 178 1.9 xtraeme if ((lerr = qop_disable(ifinfo)) != 0) 179 1.1 thorpej if (error == 0) 180 1.9 xtraeme error = lerr; 181 1.1 thorpej return (error); 182 1.1 thorpej } 183 1.1 thorpej 184 1.1 thorpej int 185 1.1 thorpej qcmd_clear(const char *ifname) 186 1.1 thorpej { 187 1.1 thorpej struct ifinfo *ifinfo; 188 1.1 thorpej int error = 0; 189 1.1 thorpej 190 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 191 1.1 thorpej error = QOPERR_BADIF; 192 1.1 thorpej 193 1.1 thorpej if (error == 0) 194 1.1 thorpej error = qop_clear(ifinfo); 195 1.1 thorpej if (error != 0) 196 1.4 itojun LOG(LOG_ERR, errno, "%s: clear failed!", qoperror(error)); 197 1.1 thorpej return (error); 198 1.1 thorpej } 199 1.1 thorpej 200 1.1 thorpej int 201 1.1 thorpej qcmd_destroyall(void) 202 1.1 thorpej { 203 1.1 thorpej while (!LIST_EMPTY(&qop_iflist)) 204 1.1 thorpej (void)qop_delete_if(LIST_FIRST(&qop_iflist)); 205 1.1 thorpej return (0); 206 1.1 thorpej } 207 1.1 thorpej 208 1.1 thorpej int 209 1.1 thorpej qcmd_restart(void) 210 1.1 thorpej { 211 1.1 thorpej qcmd_destroyall(); 212 1.1 thorpej return qcmd_init(); 213 1.1 thorpej } 214 1.1 thorpej 215 1.1 thorpej int 216 1.1 thorpej qcmd_delete_class(const char *ifname, const char *clname) 217 1.1 thorpej { 218 1.1 thorpej struct ifinfo *ifinfo; 219 1.6 he struct classinfo *clinfo = NULL; 220 1.1 thorpej int error = 0; 221 1.1 thorpej 222 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 223 1.1 thorpej error = QOPERR_BADIF; 224 1.1 thorpej 225 1.1 thorpej if (error == 0 && 226 1.1 thorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 227 1.1 thorpej error = QOPERR_BADCLASS; 228 1.1 thorpej 229 1.1 thorpej if (error == 0) 230 1.1 thorpej error = qop_delete_class(clinfo); 231 1.1 thorpej if (error != 0) 232 1.4 itojun LOG(LOG_ERR, errno, "%s: delete_class failed", 233 1.1 thorpej qoperror(error)); 234 1.1 thorpej return (error); 235 1.1 thorpej } 236 1.1 thorpej 237 1.1 thorpej int 238 1.1 thorpej qcmd_add_filter(const char *ifname, const char *clname, const char *flname, 239 1.1 thorpej const struct flow_filter *fltr) 240 1.1 thorpej { 241 1.1 thorpej struct ifinfo *ifinfo; 242 1.6 he struct classinfo *clinfo = NULL; 243 1.1 thorpej int error = 0; 244 1.1 thorpej 245 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 246 1.1 thorpej error = QOPERR_BADIF; 247 1.1 thorpej 248 1.1 thorpej if (error == 0 && 249 1.1 thorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) { 250 1.1 thorpej /* 251 1.1 thorpej * there is no matching class. 252 1.1 thorpej * check if it is for a traffic conditioner 253 1.1 thorpej */ 254 1.1 thorpej if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL || 255 1.1 thorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 256 1.1 thorpej error = QOPERR_BADCLASS; 257 1.1 thorpej } 258 1.1 thorpej 259 1.1 thorpej if (error == 0) 260 1.1 thorpej error = qop_add_filter(NULL, clinfo, flname, fltr, NULL); 261 1.1 thorpej 262 1.1 thorpej if (error != 0) 263 1.4 itojun LOG(LOG_ERR, errno, "%s: add filter failed!", 264 1.1 thorpej qoperror(error)); 265 1.1 thorpej else if (IsDebug(DEBUG_ALTQ)) { 266 1.4 itojun LOG(LOG_DEBUG, 0, "%s: add a filter %s to class %s", 267 1.1 thorpej ifname, flname ? flname : "(null)", 268 1.1 thorpej clname ? clname : "(null)"); 269 1.1 thorpej print_filter(fltr); 270 1.1 thorpej } 271 1.1 thorpej return (error); 272 1.1 thorpej } 273 1.1 thorpej 274 1.1 thorpej int 275 1.1 thorpej qcmd_delete_filter(const char *ifname, const char *clname, const char *flname) 276 1.1 thorpej { 277 1.1 thorpej struct ifinfo *ifinfo; 278 1.6 he struct classinfo *clinfo = NULL; 279 1.6 he struct fltrinfo *fltrinfo = NULL; 280 1.1 thorpej int error = 0; 281 1.1 thorpej 282 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 283 1.1 thorpej error = QOPERR_BADIF; 284 1.1 thorpej 285 1.1 thorpej if (error == 0 && 286 1.1 thorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) { 287 1.1 thorpej /* 288 1.1 thorpej * there is no matching class. 289 1.1 thorpej * check if it is for a traffic conditioner 290 1.1 thorpej */ 291 1.1 thorpej if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL || 292 1.1 thorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 293 1.1 thorpej error = QOPERR_BADCLASS; 294 1.1 thorpej } 295 1.1 thorpej 296 1.1 thorpej if (error == 0 && 297 1.1 thorpej (fltrinfo = flname2flinfo(clinfo, flname)) == NULL) 298 1.1 thorpej error = QOPERR_BADFILTER; 299 1.1 thorpej 300 1.1 thorpej if (error == 0) 301 1.1 thorpej error = qop_delete_filter(fltrinfo); 302 1.1 thorpej if (error != 0) 303 1.4 itojun LOG(LOG_ERR, errno, "%s: delete filter failed!", 304 1.1 thorpej qoperror(error)); 305 1.1 thorpej return (error); 306 1.1 thorpej } 307 1.1 thorpej 308 1.1 thorpej int 309 1.13 ozaki qcmd_tbr_register(const char *ifname, uint64_t rate, u_int size) 310 1.1 thorpej { 311 1.1 thorpej struct tbrinfo *info; 312 1.1 thorpej 313 1.1 thorpej if ((info = calloc(1, sizeof(struct tbrinfo))) == NULL) 314 1.1 thorpej return (QOPERR_NOMEM); 315 1.1 thorpej 316 1.2 itojun strlcpy(info->ifname, ifname, sizeof(info->ifname)); 317 1.1 thorpej info->tb_prof.rate = rate; 318 1.1 thorpej info->tb_prof.depth = size; 319 1.1 thorpej info->installed = 0; 320 1.1 thorpej LIST_INSERT_HEAD(&tbr_list, info, link); 321 1.1 thorpej return (0); 322 1.1 thorpej } 323 1.1 thorpej 324 1.1 thorpej /* 325 1.1 thorpej * QOP (Queue Operation) API 326 1.1 thorpej */ 327 1.1 thorpej 328 1.1 thorpej int 329 1.13 ozaki qop_add_if(struct ifinfo **rp, const char *ifname, uint64_t bandwidth, 330 1.1 thorpej struct qdisc_ops *qdisc_ops, void *if_private) 331 1.1 thorpej { 332 1.1 thorpej struct ifinfo *ifinfo; 333 1.1 thorpej int error; 334 1.1 thorpej 335 1.1 thorpej if (ifname2ifinfo(ifname) != NULL) { 336 1.4 itojun LOG(LOG_ERR, 0, "qop_add_if: %s already exists!", ifname); 337 1.1 thorpej return (QOPERR_BADIF); 338 1.1 thorpej } 339 1.1 thorpej 340 1.1 thorpej if ((ifinfo = calloc(1, sizeof(struct ifinfo))) == NULL) 341 1.1 thorpej return (QOPERR_NOMEM); 342 1.1 thorpej ifinfo->ifname = strdup(ifname); 343 1.1 thorpej ifinfo->bandwidth = bandwidth; 344 1.1 thorpej ifinfo->enabled = 0; 345 1.1 thorpej if (ifname[0] == '_') 346 1.1 thorpej /* input interface */ 347 1.1 thorpej ifname += 1; 348 1.1 thorpej ifinfo->ifindex = get_ifindex(ifname); 349 1.1 thorpej ifinfo->ifmtu = get_ifmtu(ifname); 350 1.8 peter if (qdisc_ops == NULL) 351 1.1 thorpej ifinfo->qdisc = &nop_qdisc; /* replace syscalls by nops */ 352 1.1 thorpej else 353 1.1 thorpej ifinfo->qdisc = qdisc_ops; 354 1.1 thorpej ifinfo->private = if_private; 355 1.1 thorpej LIST_INIT(&ifinfo->cllist); 356 1.1 thorpej LIST_INIT(&ifinfo->fltr_rules); 357 1.1 thorpej 358 1.1 thorpej /* Link the interface info structure */ 359 1.1 thorpej LIST_INSERT_HEAD(&qop_iflist, ifinfo, next); 360 1.1 thorpej 361 1.1 thorpej /* install token bucket regulator, if necessary */ 362 1.1 thorpej tbr_install(ifname); 363 1.1 thorpej 364 1.1 thorpej /* attach the discipline to the interface */ 365 1.1 thorpej if ((error = (*ifinfo->qdisc->attach)(ifinfo)) != 0) 366 1.1 thorpej goto err_ret; 367 1.1 thorpej 368 1.1 thorpej /* disable and clear the interface */ 369 1.1 thorpej if (ifinfo->qdisc->disable != NULL) 370 1.1 thorpej if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0) 371 1.1 thorpej goto err_ret; 372 1.1 thorpej if (ifinfo->qdisc->clear != NULL) 373 1.1 thorpej if ((error = (*ifinfo->qdisc->clear)(ifinfo)) != 0) 374 1.1 thorpej goto err_ret; 375 1.1 thorpej 376 1.1 thorpej if (rp != NULL) 377 1.1 thorpej *rp = ifinfo; 378 1.1 thorpej return (0); 379 1.1 thorpej 380 1.1 thorpej err_ret: 381 1.1 thorpej if (ifinfo != NULL) { 382 1.1 thorpej LIST_REMOVE(ifinfo, next); 383 1.1 thorpej if (ifinfo->ifname != NULL) 384 1.1 thorpej free(ifinfo->ifname); 385 1.1 thorpej free(ifinfo); 386 1.1 thorpej } 387 1.1 thorpej return (error); 388 1.1 thorpej } 389 1.1 thorpej 390 1.1 thorpej int 391 1.1 thorpej qop_delete_if(struct ifinfo *ifinfo) 392 1.1 thorpej { 393 1.1 thorpej (void)qop_disable(ifinfo); 394 1.1 thorpej (void)qop_clear(ifinfo); 395 1.1 thorpej 396 1.1 thorpej if (ifinfo->delete_hook != NULL) 397 1.1 thorpej (*ifinfo->delete_hook)(ifinfo); 398 1.1 thorpej 399 1.1 thorpej /* remove this entry from qop_iflist */ 400 1.1 thorpej LIST_REMOVE(ifinfo, next); 401 1.1 thorpej 402 1.1 thorpej (void)(*ifinfo->qdisc->detach)(ifinfo); 403 1.1 thorpej 404 1.1 thorpej /* deinstall token bucket regulator, if necessary */ 405 1.1 thorpej tbr_deinstall(ifinfo->ifname); 406 1.1 thorpej 407 1.1 thorpej if (ifinfo->private != NULL) 408 1.1 thorpej free(ifinfo->private); 409 1.1 thorpej if (ifinfo->ifname != NULL) 410 1.1 thorpej free(ifinfo->ifname); 411 1.1 thorpej free(ifinfo); 412 1.1 thorpej return (0); 413 1.1 thorpej } 414 1.1 thorpej 415 1.1 thorpej int 416 1.1 thorpej qop_enable(struct ifinfo *ifinfo) 417 1.1 thorpej { 418 1.1 thorpej int error; 419 1.1 thorpej 420 1.1 thorpej if (ifinfo->enable_hook != NULL) 421 1.1 thorpej if ((error = (*ifinfo->enable_hook)(ifinfo)) != 0) 422 1.1 thorpej return (error); 423 1.1 thorpej 424 1.1 thorpej if (ifinfo->qdisc->enable != NULL) 425 1.1 thorpej if ((error = (*ifinfo->qdisc->enable)(ifinfo)) != 0) 426 1.1 thorpej return (error); 427 1.1 thorpej ifinfo->enabled = 1; 428 1.1 thorpej return (0); 429 1.1 thorpej } 430 1.1 thorpej 431 1.1 thorpej int 432 1.1 thorpej qop_disable(struct ifinfo *ifinfo) 433 1.1 thorpej { 434 1.1 thorpej int error; 435 1.1 thorpej 436 1.1 thorpej if (ifinfo->qdisc->disable != NULL) 437 1.1 thorpej if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0) 438 1.1 thorpej return (error); 439 1.1 thorpej ifinfo->enabled = 0; 440 1.1 thorpej return (0); 441 1.1 thorpej } 442 1.1 thorpej 443 1.1 thorpej int 444 1.1 thorpej qop_clear(struct ifinfo *ifinfo) 445 1.1 thorpej { 446 1.1 thorpej struct classinfo *clinfo; 447 1.1 thorpej 448 1.1 thorpej /* free all classes and filters */ 449 1.1 thorpej if (ifinfo->ifname[0] != '_') { 450 1.1 thorpej /* output interface. delete from leaf classes */ 451 1.1 thorpej while (!LIST_EMPTY(&ifinfo->cllist)) { 452 1.1 thorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) { 453 1.1 thorpej if (clinfo->child != NULL) 454 1.1 thorpej continue; 455 1.1 thorpej qop_delete_class(clinfo); 456 1.1 thorpej /* 457 1.1 thorpej * the list has been changed, 458 1.1 thorpej * restart from the head 459 1.1 thorpej */ 460 1.1 thorpej break; 461 1.1 thorpej } 462 1.1 thorpej } 463 1.1 thorpej } else { 464 1.1 thorpej /* input interface. delete from parents */ 465 1.1 thorpej struct classinfo *root = get_rootclass(ifinfo); 466 1.1 thorpej 467 1.1 thorpej while (!LIST_EMPTY(&ifinfo->cllist)) { 468 1.1 thorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 469 1.1 thorpej if (clinfo->parent == root) { 470 1.1 thorpej qop_delete_cdnr(clinfo); 471 1.1 thorpej break; 472 1.1 thorpej } 473 1.7 christos if (root->child != NULL) 474 1.1 thorpej qop_delete_class(root); 475 1.1 thorpej } 476 1.1 thorpej } 477 1.1 thorpej 478 1.1 thorpej /* clear the interface */ 479 1.1 thorpej if (ifinfo->qdisc->clear != NULL) 480 1.1 thorpej return (*ifinfo->qdisc->clear)(ifinfo); 481 1.1 thorpej return (0); 482 1.1 thorpej } 483 1.1 thorpej 484 1.1 thorpej int 485 1.1 thorpej qop_add_class(struct classinfo **rp, const char *clname, 486 1.1 thorpej struct ifinfo *ifinfo, struct classinfo *parent, 487 1.1 thorpej void *class_private) 488 1.1 thorpej { 489 1.1 thorpej struct classinfo *clinfo; 490 1.1 thorpej int error; 491 1.1 thorpej 492 1.1 thorpej if ((clinfo = calloc(1, sizeof(*clinfo))) == NULL) 493 1.1 thorpej return (QOPERR_NOMEM); 494 1.1 thorpej 495 1.1 thorpej if (clname != NULL) 496 1.1 thorpej clinfo->clname = strdup(clname); 497 1.1 thorpej else 498 1.1 thorpej clinfo->clname = strdup("(null)"); /* dummy name */ 499 1.1 thorpej clinfo->ifinfo = ifinfo; 500 1.1 thorpej clinfo->private = class_private; 501 1.1 thorpej clinfo->parent = parent; 502 1.1 thorpej clinfo->child = NULL; 503 1.1 thorpej LIST_INIT(&clinfo->fltrlist); 504 1.1 thorpej 505 1.1 thorpej if ((error = (*ifinfo->qdisc->add_class)(clinfo)) != 0) 506 1.1 thorpej goto err_ret; 507 1.1 thorpej 508 1.1 thorpej /* link classinfo in lists */ 509 1.1 thorpej LIST_INSERT_HEAD(&ifinfo->cllist, clinfo, next); 510 1.1 thorpej 511 1.1 thorpej if (parent != NULL) { 512 1.1 thorpej clinfo->sibling = parent->child; 513 1.1 thorpej clinfo->parent->child = clinfo; 514 1.1 thorpej } 515 1.1 thorpej 516 1.1 thorpej if (rp != NULL) 517 1.1 thorpej *rp = clinfo; 518 1.1 thorpej return (0); 519 1.1 thorpej 520 1.1 thorpej err_ret: 521 1.1 thorpej if (clinfo != NULL) { 522 1.1 thorpej if (clinfo->clname != NULL) 523 1.1 thorpej free(clinfo->clname); 524 1.1 thorpej free(clinfo); 525 1.1 thorpej } 526 1.1 thorpej return (error); 527 1.1 thorpej } 528 1.1 thorpej 529 1.1 thorpej int 530 1.1 thorpej qop_modify_class(struct classinfo *clinfo, void *arg) 531 1.1 thorpej { 532 1.1 thorpej return (*clinfo->ifinfo->qdisc->modify_class)(clinfo, arg); 533 1.1 thorpej } 534 1.1 thorpej 535 1.1 thorpej int 536 1.1 thorpej qop_delete_class(struct classinfo *clinfo) 537 1.1 thorpej { 538 1.1 thorpej struct ifinfo *ifinfo = clinfo->ifinfo; 539 1.1 thorpej struct classinfo *prev; 540 1.1 thorpej int error; 541 1.1 thorpej 542 1.1 thorpej /* a class to be removed should not have a child */ 543 1.1 thorpej if (clinfo->child != NULL) 544 1.1 thorpej return (QOPERR_CLASS_PERM); 545 1.1 thorpej 546 1.1 thorpej /* remove filters associated to this class */ 547 1.1 thorpej while (!LIST_EMPTY(&clinfo->fltrlist)) 548 1.1 thorpej (void)qop_delete_filter(LIST_FIRST(&clinfo->fltrlist)); 549 1.1 thorpej 550 1.1 thorpej if (clinfo->delete_hook != NULL) 551 1.1 thorpej (*clinfo->delete_hook)(clinfo); 552 1.1 thorpej 553 1.1 thorpej /* remove class info from the interface */ 554 1.1 thorpej LIST_REMOVE(clinfo, next); 555 1.1 thorpej 556 1.1 thorpej /* remove this class from the child list */ 557 1.1 thorpej if (clinfo->parent != NULL) { 558 1.1 thorpej if (clinfo->parent->child == clinfo) 559 1.1 thorpej clinfo->parent->child = clinfo->sibling; 560 1.1 thorpej else for (prev = clinfo->parent->child; prev->sibling != NULL; 561 1.1 thorpej prev = prev->sibling) 562 1.1 thorpej if (prev->sibling == clinfo) { 563 1.1 thorpej prev->sibling = clinfo->sibling; 564 1.1 thorpej break; 565 1.1 thorpej } 566 1.1 thorpej } 567 1.1 thorpej 568 1.1 thorpej /* delete class from kernel */ 569 1.1 thorpej if ((error = (*ifinfo->qdisc->delete_class)(clinfo)) != 0) 570 1.1 thorpej return (error); 571 1.1 thorpej 572 1.1 thorpej if (clinfo->private != NULL) 573 1.1 thorpej free(clinfo->private); 574 1.1 thorpej if (clinfo->clname != NULL) 575 1.1 thorpej free(clinfo->clname); 576 1.1 thorpej free(clinfo); 577 1.1 thorpej return (0); 578 1.1 thorpej } 579 1.1 thorpej 580 1.1 thorpej int 581 1.1 thorpej qop_add_filter(struct fltrinfo **rp, struct classinfo *clinfo, 582 1.1 thorpej const char *flname, const struct flow_filter *fltr, 583 1.1 thorpej struct fltrinfo **conflict) 584 1.1 thorpej { 585 1.1 thorpej struct ifinfo *ifinfo; 586 1.1 thorpej struct fltrinfo *fltrinfo; 587 1.1 thorpej int error; 588 1.1 thorpej 589 1.1 thorpej if ((fltrinfo = calloc(1, sizeof(*fltrinfo))) == NULL) 590 1.1 thorpej return (QOPERR_NOMEM); 591 1.1 thorpej 592 1.1 thorpej fltrinfo->clinfo = clinfo; 593 1.1 thorpej fltrinfo->fltr = *fltr; 594 1.1 thorpej #if 1 595 1.1 thorpej /* fix this */ 596 1.1 thorpej fltrinfo->line_no = line_no; /* XXX */ 597 1.1 thorpej fltrinfo->dontwarn = filter_dontwarn; /* XXX */ 598 1.1 thorpej #endif 599 1.1 thorpej if (flname != NULL) 600 1.1 thorpej fltrinfo->flname = strdup(flname); 601 1.1 thorpej else 602 1.1 thorpej fltrinfo->flname = strdup("(null)"); /* dummy name */ 603 1.1 thorpej 604 1.1 thorpej /* check and save the filter */ 605 1.1 thorpej ifinfo = clinfo->ifinfo; 606 1.1 thorpej if ((error = add_filter_rule(ifinfo, fltrinfo, conflict)) != 0) 607 1.1 thorpej goto err_ret; 608 1.1 thorpej 609 1.1 thorpej /* install the filter to the kernel */ 610 1.1 thorpej if ((error = (*ifinfo->qdisc->add_filter)(fltrinfo)) != 0) { 611 1.1 thorpej remove_filter_rule(ifinfo, fltrinfo); 612 1.1 thorpej goto err_ret; 613 1.1 thorpej } 614 1.1 thorpej 615 1.1 thorpej /* link fltrinfo onto fltrlist of the class */ 616 1.1 thorpej LIST_INSERT_HEAD(&clinfo->fltrlist, fltrinfo, next); 617 1.1 thorpej 618 1.1 thorpej if (rp != NULL) 619 1.1 thorpej *rp = fltrinfo; 620 1.1 thorpej return (0); 621 1.1 thorpej 622 1.1 thorpej err_ret: 623 1.1 thorpej if (fltrinfo != NULL) { 624 1.1 thorpej if (fltrinfo->flname != NULL) 625 1.1 thorpej free(fltrinfo->flname); 626 1.1 thorpej free(fltrinfo); 627 1.1 thorpej } 628 1.1 thorpej return (error); 629 1.1 thorpej } 630 1.1 thorpej 631 1.1 thorpej int 632 1.1 thorpej qop_delete_filter(struct fltrinfo *fltrinfo) 633 1.1 thorpej { 634 1.1 thorpej struct ifinfo *ifinfo; 635 1.1 thorpej struct classinfo *clinfo; 636 1.1 thorpej int error; 637 1.1 thorpej 638 1.1 thorpej /* remove filter info from the class */ 639 1.1 thorpej clinfo = fltrinfo->clinfo; 640 1.1 thorpej ifinfo = clinfo->ifinfo; 641 1.1 thorpej 642 1.1 thorpej 643 1.1 thorpej /* remove the entry from fltrlist of the class */ 644 1.1 thorpej LIST_REMOVE(fltrinfo, next); 645 1.1 thorpej 646 1.1 thorpej remove_filter_rule(ifinfo, fltrinfo); 647 1.1 thorpej 648 1.1 thorpej /* delete filter from kernel */ 649 1.1 thorpej if ((error = (*ifinfo->qdisc->delete_filter)(fltrinfo)) != 0) 650 1.1 thorpej return (error); 651 1.1 thorpej 652 1.1 thorpej if (fltrinfo->flname) 653 1.1 thorpej free(fltrinfo->flname); 654 1.1 thorpej free(fltrinfo); 655 1.1 thorpej return (0); 656 1.1 thorpej } 657 1.1 thorpej 658 1.1 thorpej const char * 659 1.1 thorpej qoperror(int qoperrno) 660 1.1 thorpej { 661 1.1 thorpej static char buf[64]; 662 1.1 thorpej 663 1.1 thorpej if (qoperrno <= QOPERR_MAX) 664 1.1 thorpej return (qop_errlist[qoperrno]); 665 1.2 itojun snprintf(buf, sizeof(buf), "unknown error %d", qoperrno); 666 1.1 thorpej return (buf); 667 1.1 thorpej } 668 1.1 thorpej 669 1.1 thorpej /* 670 1.1 thorpej * misc functions 671 1.1 thorpej */ 672 1.1 thorpej struct ifinfo * 673 1.1 thorpej ifname2ifinfo(const char *ifname) 674 1.1 thorpej { 675 1.1 thorpej struct ifinfo *ifinfo; 676 1.1 thorpej 677 1.1 thorpej LIST_FOREACH(ifinfo, &qop_iflist, next) 678 1.1 thorpej if (ifinfo->ifname != NULL && 679 1.1 thorpej strcmp(ifinfo->ifname, ifname) == 0) 680 1.1 thorpej return (ifinfo); 681 1.1 thorpej return (NULL); 682 1.1 thorpej } 683 1.1 thorpej 684 1.1 thorpej struct ifinfo * 685 1.1 thorpej input_ifname2ifinfo(const char *ifname) 686 1.1 thorpej { 687 1.1 thorpej struct ifinfo *ifinfo; 688 1.1 thorpej 689 1.1 thorpej LIST_FOREACH(ifinfo, &qop_iflist, next) 690 1.1 thorpej if (ifinfo->ifname[0] == '_' && 691 1.1 thorpej strcmp(ifinfo->ifname+1, ifname) == 0) 692 1.1 thorpej return (ifinfo); 693 1.1 thorpej return (NULL); 694 1.1 thorpej } 695 1.1 thorpej 696 1.1 thorpej struct classinfo * 697 1.1 thorpej clname2clinfo(const struct ifinfo *ifinfo, const char *clname) 698 1.1 thorpej { 699 1.1 thorpej struct classinfo *clinfo; 700 1.1 thorpej 701 1.1 thorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 702 1.1 thorpej if (clinfo->clname != NULL && 703 1.1 thorpej strcmp(clinfo->clname, clname) == 0) 704 1.1 thorpej return (clinfo); 705 1.1 thorpej return (NULL); 706 1.1 thorpej } 707 1.1 thorpej 708 1.1 thorpej struct classinfo * 709 1.1 thorpej clhandle2clinfo(struct ifinfo *ifinfo, u_long handle) 710 1.1 thorpej { 711 1.1 thorpej struct classinfo *clinfo; 712 1.1 thorpej 713 1.1 thorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 714 1.1 thorpej if (clinfo->handle == handle) 715 1.1 thorpej return (clinfo); 716 1.1 thorpej return (NULL); 717 1.1 thorpej } 718 1.1 thorpej 719 1.1 thorpej struct fltrinfo * 720 1.1 thorpej flname2flinfo(const struct classinfo *clinfo, const char *flname) 721 1.1 thorpej { 722 1.1 thorpej struct fltrinfo *fltrinfo; 723 1.1 thorpej 724 1.1 thorpej LIST_FOREACH(fltrinfo, &clinfo->fltrlist, next) 725 1.1 thorpej if (fltrinfo->flname != NULL && 726 1.1 thorpej strcmp(fltrinfo->flname, flname) == 0) 727 1.1 thorpej return (fltrinfo); 728 1.1 thorpej return (NULL); 729 1.1 thorpej } 730 1.1 thorpej 731 1.1 thorpej struct fltrinfo * 732 1.1 thorpej flhandle2fltrinfo(struct ifinfo *ifinfo, u_long handle) 733 1.1 thorpej { 734 1.1 thorpej struct fltrinfo *fltrinfo; 735 1.1 thorpej 736 1.1 thorpej LIST_FOREACH(fltrinfo, &ifinfo->fltr_rules, nextrule) 737 1.1 thorpej if (fltrinfo->handle == handle) 738 1.1 thorpej return (fltrinfo); 739 1.1 thorpej return (NULL); 740 1.1 thorpej } 741 1.1 thorpej 742 1.1 thorpej int 743 1.1 thorpej is_q_enabled(const char *ifname) 744 1.1 thorpej { 745 1.1 thorpej struct ifinfo *ifinfo; 746 1.1 thorpej 747 1.1 thorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 748 1.1 thorpej return (0); 749 1.1 thorpej return (ifinfo->enabled); 750 1.1 thorpej } 751 1.1 thorpej 752 1.1 thorpej /* 753 1.1 thorpej * functions to walk through a class tree: 754 1.1 thorpej * 755 1.1 thorpej * for (clinfo = get_rootclass(ifinfo); 756 1.1 thorpej * clinfo != NULL; clinfo = get_nextclass(clinfo)) { 757 1.1 thorpej * do_something; 758 1.1 thorpej * } 759 1.1 thorpej */ 760 1.1 thorpej struct classinfo *get_rootclass(struct ifinfo *ifinfo) 761 1.1 thorpej { 762 1.1 thorpej struct classinfo *clinfo; 763 1.1 thorpej 764 1.1 thorpej /* find a class without parent */ 765 1.1 thorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 766 1.1 thorpej if (clinfo->parent == NULL) 767 1.1 thorpej return (clinfo); 768 1.1 thorpej return (NULL); 769 1.1 thorpej } 770 1.1 thorpej 771 1.1 thorpej /* return next class in the tree */ 772 1.1 thorpej struct classinfo *get_nextclass(struct classinfo *clinfo) 773 1.1 thorpej { 774 1.1 thorpej struct classinfo *next; 775 1.1 thorpej 776 1.1 thorpej if (clinfo->child != NULL) 777 1.1 thorpej next = clinfo->child; 778 1.1 thorpej else if (clinfo->sibling != NULL) 779 1.1 thorpej next = clinfo->sibling; 780 1.1 thorpej else { 781 1.1 thorpej next = clinfo; 782 1.1 thorpej while ((next = next->parent) != NULL) 783 1.1 thorpej if (next->sibling) { 784 1.1 thorpej next = next->sibling; 785 1.1 thorpej break; 786 1.1 thorpej } 787 1.1 thorpej } 788 1.1 thorpej return (next); 789 1.1 thorpej } 790 1.1 thorpej 791 1.13 ozaki uint64_t 792 1.1 thorpej atobps(const char *s) 793 1.1 thorpej { 794 1.5 itojun double bandwidth; 795 1.1 thorpej char *cp; 796 1.1 thorpej 797 1.5 itojun bandwidth = strtod(s, &cp); 798 1.1 thorpej if (cp != NULL) { 799 1.1 thorpej if (*cp == 'K' || *cp == 'k') 800 1.1 thorpej bandwidth *= 1000; 801 1.1 thorpej else if (*cp == 'M' || *cp == 'm') 802 1.1 thorpej bandwidth *= 1000000; 803 1.1 thorpej else if (*cp == 'G' || *cp == 'g') 804 1.1 thorpej bandwidth *= 1000000000; 805 1.1 thorpej } 806 1.5 itojun if (bandwidth < 0) 807 1.5 itojun bandwidth = 0; 808 1.13 ozaki return ((uint64_t)bandwidth); 809 1.1 thorpej } 810 1.1 thorpej 811 1.1 thorpej u_long 812 1.1 thorpej atobytes(const char *s) 813 1.1 thorpej { 814 1.5 itojun double bytes; 815 1.1 thorpej char *cp; 816 1.1 thorpej 817 1.5 itojun bytes = strtod(s, &cp); 818 1.1 thorpej if (cp != NULL) { 819 1.1 thorpej if (*cp == 'K' || *cp == 'k') 820 1.1 thorpej bytes *= 1024; 821 1.1 thorpej else if (*cp == 'M' || *cp == 'm') 822 1.1 thorpej bytes *= 1024 * 1024; 823 1.1 thorpej else if (*cp == 'G' || *cp == 'g') 824 1.1 thorpej bytes *= 1024 * 1024 * 1024; 825 1.1 thorpej } 826 1.5 itojun if (bytes < 0) 827 1.5 itojun bytes = 0; 828 1.5 itojun return ((u_long)bytes); 829 1.1 thorpej } 830 1.1 thorpej 831 1.1 thorpej static int 832 1.1 thorpej get_ifmtu(const char *ifname) 833 1.1 thorpej { 834 1.1 thorpej int s, mtu; 835 1.1 thorpej struct ifreq ifr; 836 1.1 thorpej #ifdef __OpenBSD__ 837 1.1 thorpej struct if_data ifdata; 838 1.1 thorpej #endif 839 1.1 thorpej 840 1.1 thorpej mtu = 512; /* default MTU */ 841 1.1 thorpej 842 1.1 thorpej if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 843 1.1 thorpej return (mtu); 844 1.1 thorpej strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 845 1.1 thorpej #ifdef __OpenBSD__ 846 1.1 thorpej ifr.ifr_data = (caddr_t)&ifdata; 847 1.1 thorpej if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0) 848 1.1 thorpej mtu = ifdata.ifi_mtu; 849 1.1 thorpej #else 850 1.1 thorpej if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) 851 1.1 thorpej mtu = ifr.ifr_mtu; 852 1.1 thorpej #endif 853 1.1 thorpej close(s); 854 1.1 thorpej return (mtu); 855 1.1 thorpej } 856 1.1 thorpej 857 1.1 thorpej static void 858 1.1 thorpej tbr_install(const char *ifname) 859 1.1 thorpej { 860 1.1 thorpej struct tbrinfo *info; 861 1.1 thorpej struct tbrreq req; 862 1.1 thorpej int fd; 863 1.1 thorpej 864 1.1 thorpej LIST_FOREACH(info, &tbr_list, link) 865 1.1 thorpej if (strcmp(info->ifname, ifname) == 0) 866 1.1 thorpej break; 867 1.1 thorpej if (info == NULL) 868 1.1 thorpej return; 869 1.1 thorpej if (info->tb_prof.rate == 0 || info->installed) 870 1.1 thorpej return; 871 1.1 thorpej 872 1.1 thorpej /* get the current token bucket regulator */ 873 1.1 thorpej if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 874 1.1 thorpej err(1, "can't open altq device"); 875 1.1 thorpej strncpy(req.ifname, ifname, IFNAMSIZ-1); 876 1.1 thorpej if (ioctl(fd, ALTQTBRGET, &req) < 0) 877 1.1 thorpej err(1, "ALTQTBRGET for interface %s", req.ifname); 878 1.1 thorpej 879 1.1 thorpej /* save the current values */ 880 1.1 thorpej info->otb_prof.rate = req.tb_prof.rate; 881 1.1 thorpej info->otb_prof.depth = req.tb_prof.depth; 882 1.1 thorpej 883 1.1 thorpej /* 884 1.1 thorpej * if tbr is not specified in the config file and tbr is already 885 1.1 thorpej * configured, do not change. 886 1.1 thorpej */ 887 1.1 thorpej if (req.tb_prof.rate != 0) { 888 1.1 thorpej LOG(LOG_INFO, 0, 889 1.1 thorpej "tbr is already installed on %s,\n" 890 1.4 itojun " using the current setting (rate:%.2fM size:%.2fK).", 891 1.1 thorpej info->ifname, 892 1.1 thorpej (double)req.tb_prof.rate/1000000.0, 893 1.1 thorpej (double)req.tb_prof.depth/1024.0); 894 1.1 thorpej close (fd); 895 1.1 thorpej return; 896 1.1 thorpej } 897 1.1 thorpej 898 1.1 thorpej /* if the new size is not specified, use heuristics */ 899 1.1 thorpej if (info->tb_prof.depth == 0) { 900 1.1 thorpej u_int rate, size; 901 1.1 thorpej 902 1.1 thorpej rate = info->tb_prof.rate; 903 1.1 thorpej if (rate <= 1*1000*1000) 904 1.1 thorpej size = 1; 905 1.1 thorpej else if (rate <= 10*1000*1000) 906 1.1 thorpej size = 4; 907 1.1 thorpej else if (rate <= 200*1000*1000) 908 1.1 thorpej size = 8; 909 1.1 thorpej else 910 1.1 thorpej size = 24; 911 1.1 thorpej size = size * 1500; /* assume the default mtu is 1500 */ 912 1.1 thorpej info->tb_prof.depth = size; 913 1.1 thorpej } 914 1.1 thorpej 915 1.1 thorpej /* install the new tbr */ 916 1.1 thorpej strncpy(req.ifname, ifname, IFNAMSIZ-1); 917 1.1 thorpej req.tb_prof.rate = info->tb_prof.rate; 918 1.1 thorpej req.tb_prof.depth = info->tb_prof.depth; 919 1.1 thorpej if (ioctl(fd, ALTQTBRSET, &req) < 0) 920 1.1 thorpej err(1, "ALTQTBRSET for interface %s", req.ifname); 921 1.1 thorpej LOG(LOG_INFO, 0, 922 1.4 itojun "tbr installed on %s (rate:%.2fM size:%.2fK)", 923 1.1 thorpej info->ifname, 924 1.1 thorpej (double)info->tb_prof.rate/1000000.0, 925 1.1 thorpej (double)info->tb_prof.depth/1024.0); 926 1.1 thorpej close(fd); 927 1.1 thorpej info->installed = 1; 928 1.1 thorpej } 929 1.1 thorpej 930 1.1 thorpej static void 931 1.1 thorpej tbr_deinstall(const char *ifname) 932 1.1 thorpej { 933 1.1 thorpej struct tbrinfo *info; 934 1.1 thorpej struct tbrreq req; 935 1.1 thorpej int fd; 936 1.1 thorpej 937 1.1 thorpej LIST_FOREACH(info, &tbr_list, link) 938 1.1 thorpej if (strcmp(info->ifname, ifname) == 0) 939 1.1 thorpej break; 940 1.1 thorpej if (info == NULL) 941 1.1 thorpej return; 942 1.1 thorpej 943 1.1 thorpej /* if we installed tbr, restore the old values */ 944 1.1 thorpej if (info->installed != 0) { 945 1.1 thorpej strncpy(req.ifname, ifname, IFNAMSIZ-1); 946 1.1 thorpej req.tb_prof.rate = info->otb_prof.rate; 947 1.1 thorpej req.tb_prof.depth = info->otb_prof.depth; 948 1.1 thorpej if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 949 1.1 thorpej err(1, "can't open altq device"); 950 1.1 thorpej if (ioctl(fd, ALTQTBRSET, &req) < 0) 951 1.1 thorpej err(1, "ALTQTBRSET for interface %s", req.ifname); 952 1.1 thorpej close(fd); 953 1.1 thorpej } 954 1.1 thorpej LIST_REMOVE(info, link); 955 1.1 thorpej free(info); 956 1.1 thorpej } 957 1.1 thorpej 958 1.1 thorpej void 959 1.1 thorpej print_filter(const struct flow_filter *filt) 960 1.1 thorpej { 961 1.1 thorpej if (filt->ff_flow.fi_family == AF_INET) { 962 1.1 thorpej struct in_addr in_addr; 963 1.1 thorpej 964 1.1 thorpej in_addr.s_addr = filt->ff_flow.fi_dst.s_addr; 965 1.1 thorpej LOG(LOG_DEBUG, 0, 966 1.4 itojun " Filter Dest Addr: %s (mask %#x) Port: %d", 967 1.1 thorpej inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_dst.s_addr), 968 1.1 thorpej ntoh16(filt->ff_flow.fi_dport)); 969 1.1 thorpej in_addr.s_addr = filt->ff_flow.fi_src.s_addr; 970 1.1 thorpej LOG(LOG_DEBUG, 0, 971 1.4 itojun " Src Addr: %s (mask %#x) Port: %d", 972 1.1 thorpej inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_src.s_addr), 973 1.1 thorpej ntoh16(filt->ff_flow.fi_sport)); 974 1.4 itojun LOG(LOG_DEBUG, 0, " Protocol: %d TOS %#x (mask %#x)", 975 1.1 thorpej filt->ff_flow.fi_proto, filt->ff_flow.fi_tos, 976 1.1 thorpej filt->ff_mask.mask_tos); 977 1.1 thorpej } 978 1.1 thorpej #ifdef INET6 979 1.1 thorpej else if (filt->ff_flow.fi_family == AF_INET6) { 980 1.1 thorpej char str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN]; 981 1.1 thorpej const struct flow_filter6 *sfilt6; 982 1.1 thorpej 983 1.1 thorpej sfilt6 = (const struct flow_filter6 *)filt; 984 1.1 thorpej LOG(LOG_DEBUG, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d", 985 1.1 thorpej inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_dst, 986 1.1 thorpej str1, sizeof(str1)), 987 1.1 thorpej inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_dst, 988 1.1 thorpej str2, sizeof(str2)), 989 1.1 thorpej ntoh16(sfilt6->ff_flow6.fi6_dport)); 990 1.1 thorpej LOG(LOG_DEBUG, 0, " Src Addr: %s (mask %s) Port: %d", 991 1.1 thorpej inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_src, 992 1.1 thorpej str1, sizeof(str1)), 993 1.1 thorpej inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_src, 994 1.1 thorpej str2, sizeof(str2)), 995 1.1 thorpej ntoh16(sfilt6->ff_flow6.fi6_sport)); 996 1.4 itojun LOG(LOG_DEBUG, 0, " Protocol: %d TCLASS %#x (mask %#x)", 997 1.1 thorpej sfilt6->ff_flow6.fi6_proto, sfilt6->ff_flow6.fi6_tclass, 998 1.1 thorpej sfilt6->ff_mask6.mask6_tclass); 999 1.1 thorpej } 1000 1.1 thorpej #endif /* INET6 */ 1001 1.1 thorpej } 1002 1.1 thorpej 1003 1.1 thorpej /* 1004 1.1 thorpej * functions to check the filter-rules. 1005 1.1 thorpej * when a new filter is added, we check the relation to the existing filters 1006 1.1 thorpej * and if some inconsistency is found, produce an error or a warning message. 1007 1.1 thorpej * 1008 1.1 thorpej * filter matching is performed from the head of the list. 1009 1.1 thorpej * let 1010 1.1 thorpej * S: a set of packets that filter s matches 1011 1.1 thorpej * T: a set of packets that filter t matches 1012 1.1 thorpej * filter relations are: 1013 1.1 thorpej * disjoint: S ^ T = empty 1014 1.1 thorpej * subset: S <= T 1015 1.1 thorpej * intersect: S ^ T = not empty 1016 1.1 thorpej * 1017 1.1 thorpej * a new filter is disjoint or subset of the existing filters --> ok 1018 1.1 thorpej * a new filter is superset of an existing filter --> order problem 1019 1.1 thorpej * a new filter intersect an existing filter --> warning 1020 1.1 thorpej * 1021 1.1 thorpej * port-intersect: a special case we don't make warning 1022 1.1 thorpej * - intersection is only port numbers 1023 1.1 thorpej * - one specifies src port and the other specifies dst port 1024 1.1 thorpej * there must be no packet with well-known port numbers in 1025 1.1 thorpej * both src and dst ports. so this is ok. 1026 1.1 thorpej */ 1027 1.1 thorpej 1028 1.1 thorpej #define FILT_DISJOINT 1 1029 1.1 thorpej #define FILT_SUBSET 2 1030 1.1 thorpej #define FILT_SUPERSET 3 1031 1.1 thorpej #define FILT_INTERSECT 4 1032 1.1 thorpej #define FILT_PORTINTERSECT 5 1033 1.1 thorpej 1034 1.1 thorpej static int 1035 1.1 thorpej add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo, 1036 1.1 thorpej struct fltrinfo **conflict) 1037 1.1 thorpej { 1038 1.1 thorpej struct fltrinfo *fp, *front, *back, *prev = NULL; 1039 1.1 thorpej int relation; 1040 1.1 thorpej 1041 1.1 thorpej LIST_FOREACH(fp, &ifinfo->fltr_rules, nextrule) { 1042 1.1 thorpej if (fp->fltr.ff_ruleno > fltrinfo->fltr.ff_ruleno) { 1043 1.1 thorpej front = fp; 1044 1.1 thorpej back = fltrinfo; 1045 1.1 thorpej prev = fp; 1046 1.1 thorpej } else { 1047 1.1 thorpej front = fltrinfo; 1048 1.1 thorpej back = fp; 1049 1.1 thorpej } 1050 1.1 thorpej 1051 1.1 thorpej relation = filt_check_relation(&front->fltr, &back->fltr); 1052 1.1 thorpej 1053 1.1 thorpej switch (relation) { 1054 1.1 thorpej case FILT_SUBSET: 1055 1.1 thorpej case FILT_DISJOINT: 1056 1.1 thorpej /* OK */ 1057 1.1 thorpej break; 1058 1.1 thorpej case FILT_SUPERSET: 1059 1.1 thorpej if (front->dontwarn == 0 && back->dontwarn == 0) 1060 1.1 thorpej LOG(LOG_ERR, 0, 1061 1.4 itojun "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!", 1062 1.1 thorpej front->clinfo->clname, front->line_no, 1063 1.1 thorpej back->clinfo->clname, back->line_no); 1064 1.1 thorpej 1065 1.1 thorpej if (conflict != NULL) 1066 1.1 thorpej *conflict = fp; 1067 1.1 thorpej return (QOPERR_FILTER_SHADOW); 1068 1.1 thorpej case FILT_PORTINTERSECT: 1069 1.1 thorpej break; 1070 1.1 thorpej case FILT_INTERSECT: 1071 1.1 thorpej /* 1072 1.12 andvar * if the intersecting two filters belonging to the 1073 1.1 thorpej * same class, it's ok. 1074 1.1 thorpej */ 1075 1.1 thorpej if (front->clinfo == back->clinfo) 1076 1.1 thorpej break; 1077 1.1 thorpej if (front->dontwarn == 0 && back->dontwarn == 0) 1078 1.1 thorpej LOG(LOG_WARNING, 0, 1079 1.4 itojun "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d", 1080 1.1 thorpej front->clinfo->clname, front->line_no, 1081 1.1 thorpej back->clinfo->clname, back->line_no); 1082 1.1 thorpej break; 1083 1.1 thorpej } 1084 1.1 thorpej } 1085 1.1 thorpej 1086 1.1 thorpej if (prev == NULL) 1087 1.1 thorpej LIST_INSERT_HEAD(&ifinfo->fltr_rules, fltrinfo, nextrule); 1088 1.1 thorpej else 1089 1.1 thorpej LIST_INSERT_AFTER(prev, fltrinfo, nextrule); 1090 1.1 thorpej return (0); 1091 1.1 thorpej } 1092 1.1 thorpej 1093 1.1 thorpej static int 1094 1.1 thorpej remove_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo) 1095 1.1 thorpej { 1096 1.1 thorpej LIST_REMOVE(fltrinfo, nextrule); 1097 1.1 thorpej return (0); 1098 1.1 thorpej } 1099 1.1 thorpej 1100 1.1 thorpej static int 1101 1.1 thorpej filt_check_relation(struct flow_filter *front, struct flow_filter *back) 1102 1.1 thorpej { 1103 1.1 thorpej int rval; 1104 1.1 thorpej 1105 1.1 thorpej if (front->ff_flow.fi_family != back->ff_flow.fi_family) 1106 1.1 thorpej return (FILT_DISJOINT); 1107 1.1 thorpej 1108 1.1 thorpej if (filt_disjoint(front, back)) 1109 1.1 thorpej return (FILT_DISJOINT); 1110 1.1 thorpej 1111 1.1 thorpej if ((rval = filt_subset(front, back)) == 1) 1112 1.1 thorpej return (FILT_SUBSET); 1113 1.1 thorpej 1114 1.1 thorpej if (filt_subset(back, front) == 1) 1115 1.1 thorpej return (FILT_SUPERSET); 1116 1.1 thorpej 1117 1.1 thorpej if (rval == 2) 1118 1.1 thorpej return (FILT_PORTINTERSECT); 1119 1.1 thorpej 1120 1.1 thorpej return (FILT_INTERSECT); 1121 1.1 thorpej } 1122 1.1 thorpej 1123 1.1 thorpej static int 1124 1.1 thorpej filt_disjoint(struct flow_filter *front, struct flow_filter *back) 1125 1.1 thorpej { 1126 1.1 thorpej u_int32_t mask; 1127 1.1 thorpej u_int8_t tosmask; 1128 1.1 thorpej 1129 1.1 thorpej if (front->ff_flow.fi_family == AF_INET) { 1130 1.1 thorpej if (front->ff_flow.fi_proto != 0 && back->ff_flow.fi_proto != 0 1131 1.1 thorpej && front->ff_flow.fi_proto != back->ff_flow.fi_proto) 1132 1.1 thorpej return (1); 1133 1.1 thorpej if (front->ff_flow.fi_sport != 0 && back->ff_flow.fi_sport != 0 1134 1.1 thorpej && front->ff_flow.fi_sport != back->ff_flow.fi_sport) 1135 1.1 thorpej return (1); 1136 1.1 thorpej if (front->ff_flow.fi_dport != 0 && back->ff_flow.fi_dport != 0 1137 1.1 thorpej && front->ff_flow.fi_dport != back->ff_flow.fi_dport) 1138 1.1 thorpej return (1); 1139 1.1 thorpej if (front->ff_flow.fi_gpi != 0 && back->ff_flow.fi_gpi != 0 1140 1.1 thorpej && front->ff_flow.fi_gpi != back->ff_flow.fi_gpi) 1141 1.1 thorpej return (1); 1142 1.1 thorpej if (front->ff_flow.fi_src.s_addr != 0 && 1143 1.1 thorpej back->ff_flow.fi_src.s_addr != 0) { 1144 1.1 thorpej mask = front->ff_mask.mask_src.s_addr & 1145 1.1 thorpej back->ff_mask.mask_src.s_addr; 1146 1.1 thorpej if ((front->ff_flow.fi_src.s_addr & mask) != 1147 1.1 thorpej (back->ff_flow.fi_src.s_addr & mask)) 1148 1.1 thorpej return (1); 1149 1.1 thorpej } 1150 1.1 thorpej if (front->ff_flow.fi_dst.s_addr != 0 && 1151 1.1 thorpej back->ff_flow.fi_dst.s_addr != 0) { 1152 1.1 thorpej mask = front->ff_mask.mask_dst.s_addr & 1153 1.1 thorpej back->ff_mask.mask_dst.s_addr; 1154 1.1 thorpej if ((front->ff_flow.fi_dst.s_addr & mask) != 1155 1.1 thorpej (back->ff_flow.fi_dst.s_addr & mask)) 1156 1.1 thorpej return (1); 1157 1.1 thorpej } 1158 1.1 thorpej if (front->ff_flow.fi_tos != 0 && back->ff_flow.fi_tos != 0) { 1159 1.1 thorpej tosmask = front->ff_mask.mask_tos & 1160 1.1 thorpej back->ff_mask.mask_tos; 1161 1.1 thorpej if ((front->ff_flow.fi_tos & tosmask) != 1162 1.1 thorpej (back->ff_flow.fi_tos & tosmask)) 1163 1.1 thorpej return (1); 1164 1.1 thorpej } 1165 1.1 thorpej return (0); 1166 1.1 thorpej } 1167 1.1 thorpej #ifdef INET6 1168 1.1 thorpej else if (front->ff_flow.fi_family == AF_INET6) { 1169 1.1 thorpej struct flow_filter6 *front6, *back6; 1170 1.1 thorpej int i; 1171 1.1 thorpej 1172 1.1 thorpej front6 = (struct flow_filter6 *)front; 1173 1.1 thorpej back6 = (struct flow_filter6 *)back; 1174 1.1 thorpej 1175 1.1 thorpej if (front6->ff_flow6.fi6_proto != 0 && 1176 1.1 thorpej back6->ff_flow6.fi6_proto != 0 && 1177 1.1 thorpej front6->ff_flow6.fi6_proto != back6->ff_flow6.fi6_proto) 1178 1.1 thorpej return (1); 1179 1.1 thorpej if (front6->ff_flow6.fi6_flowlabel != 0 && 1180 1.1 thorpej back6->ff_flow6.fi6_flowlabel != 0 && 1181 1.1 thorpej front6->ff_flow6.fi6_flowlabel != 1182 1.1 thorpej back6->ff_flow6.fi6_flowlabel) 1183 1.1 thorpej return (1); 1184 1.1 thorpej if (front6->ff_flow6.fi6_sport != 0 && 1185 1.1 thorpej back6->ff_flow6.fi6_sport != 0 && 1186 1.1 thorpej front6->ff_flow6.fi6_sport != back6->ff_flow6.fi6_sport) 1187 1.1 thorpej return (1); 1188 1.1 thorpej if (front6->ff_flow6.fi6_dport != 0 && 1189 1.1 thorpej back6->ff_flow6.fi6_dport != 0 && 1190 1.1 thorpej front6->ff_flow6.fi6_dport != back6->ff_flow6.fi6_dport) 1191 1.1 thorpej return (1); 1192 1.1 thorpej if (front6->ff_flow6.fi6_gpi != 0 && 1193 1.1 thorpej back6->ff_flow6.fi6_gpi != 0 && 1194 1.1 thorpej front6->ff_flow6.fi6_gpi != back6->ff_flow6.fi6_gpi) 1195 1.1 thorpej return (1); 1196 1.1 thorpej if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src) && 1197 1.1 thorpej !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) { 1198 1.1 thorpej for (i=0; i<4; i++) { 1199 1.11 christos mask = IN6ADDR32_GET(&front6->ff_mask6.mask6_src, i) 1200 1.11 christos & IN6ADDR32_GET(&back6->ff_mask6.mask6_src, i); 1201 1.11 christos if ((IN6ADDR32_GET(&front6->ff_flow6.fi6_src, i) & mask) != 1202 1.11 christos (IN6ADDR32_GET(&back6->ff_flow6.fi6_src, i) & mask)) 1203 1.1 thorpej return (1); 1204 1.1 thorpej } 1205 1.1 thorpej } 1206 1.1 thorpej if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst) && 1207 1.1 thorpej !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) { 1208 1.1 thorpej for (i=0; i<4; i++) { 1209 1.11 christos mask = IN6ADDR32_GET(&front6->ff_mask6.mask6_dst, i) 1210 1.11 christos & IN6ADDR32_GET(&back6->ff_mask6.mask6_dst, i); 1211 1.11 christos if ((IN6ADDR32_GET(&front6->ff_flow6.fi6_dst, i) & mask) != 1212 1.11 christos (IN6ADDR32_GET(&back6->ff_flow6.fi6_dst, i) & mask)) 1213 1.1 thorpej return (1); 1214 1.1 thorpej } 1215 1.1 thorpej } 1216 1.1 thorpej if (front6->ff_flow6.fi6_tclass != 0 && 1217 1.1 thorpej back6->ff_flow6.fi6_tclass != 0) { 1218 1.1 thorpej tosmask = front6->ff_mask6.mask6_tclass & 1219 1.1 thorpej back6->ff_mask6.mask6_tclass; 1220 1.1 thorpej if ((front6->ff_flow6.fi6_tclass & tosmask) != 1221 1.1 thorpej (back6->ff_flow6.fi6_tclass & tosmask)) 1222 1.1 thorpej return (1); 1223 1.1 thorpej } 1224 1.1 thorpej return (0); 1225 1.1 thorpej } 1226 1.1 thorpej #endif /* INET6 */ 1227 1.1 thorpej return (0); 1228 1.1 thorpej } 1229 1.1 thorpej 1230 1.1 thorpej /* 1231 1.1 thorpej * check if "front" is a subset of "back". assumes they are not disjoint 1232 1.1 thorpej * return value 0: not a subset 1233 1.1 thorpej * 1: subset 1234 1.1 thorpej * 2: subset except src & dst ports 1235 1.1 thorpej * (possible port-intersect) 1236 1.1 thorpej */ 1237 1.1 thorpej static int 1238 1.1 thorpej filt_subset(struct flow_filter *front, struct flow_filter *back) 1239 1.1 thorpej { 1240 1.1 thorpej u_int16_t srcport, dstport; 1241 1.1 thorpej 1242 1.1 thorpej if (front->ff_flow.fi_family == AF_INET) { 1243 1.1 thorpej if (front->ff_flow.fi_proto == 0 && 1244 1.1 thorpej back->ff_flow.fi_proto != 0) 1245 1.1 thorpej return (0); 1246 1.1 thorpej if (front->ff_flow.fi_gpi == 0 && back->ff_flow.fi_gpi != 0) 1247 1.1 thorpej return (0); 1248 1.1 thorpej if (front->ff_flow.fi_src.s_addr == 0) { 1249 1.1 thorpej if (back->ff_flow.fi_src.s_addr != 0) 1250 1.1 thorpej return (0); 1251 1.1 thorpej } else if (back->ff_flow.fi_src.s_addr != 0 && 1252 1.1 thorpej (~front->ff_mask.mask_src.s_addr & 1253 1.1 thorpej back->ff_mask.mask_src.s_addr)) 1254 1.1 thorpej return (0); 1255 1.1 thorpej if (front->ff_flow.fi_dst.s_addr == 0) { 1256 1.1 thorpej if (back->ff_flow.fi_dst.s_addr != 0) 1257 1.1 thorpej return (0); 1258 1.1 thorpej } else if (back->ff_flow.fi_dst.s_addr != 0 && 1259 1.1 thorpej (~front->ff_mask.mask_dst.s_addr & 1260 1.1 thorpej back->ff_mask.mask_dst.s_addr)) 1261 1.1 thorpej return (0); 1262 1.1 thorpej if (~front->ff_mask.mask_tos & back->ff_mask.mask_tos) 1263 1.1 thorpej return (0); 1264 1.1 thorpej 1265 1.1 thorpej if (front->ff_flow.fi_sport == 0 && 1266 1.1 thorpej back->ff_flow.fi_sport != 0) { 1267 1.1 thorpej srcport = ntohs(back->ff_flow.fi_sport); 1268 1.1 thorpej dstport = ntohs(front->ff_flow.fi_dport); 1269 1.1 thorpej if (dstport > 0 /* && dstport < 1024 */ && 1270 1.1 thorpej srcport > 0 /* && srcport < 1024 */) 1271 1.1 thorpej return (2); 1272 1.1 thorpej return (0); 1273 1.1 thorpej } 1274 1.1 thorpej if (front->ff_flow.fi_dport == 0 && 1275 1.1 thorpej back->ff_flow.fi_dport != 0) { 1276 1.1 thorpej dstport = ntohs(back->ff_flow.fi_dport); 1277 1.1 thorpej srcport = ntohs(front->ff_flow.fi_sport); 1278 1.1 thorpej if (srcport > 0 /* && srcport < 1024 */ && 1279 1.1 thorpej dstport > 0 /* && dstport < 1024 */) 1280 1.1 thorpej return (2); 1281 1.1 thorpej return (0); 1282 1.1 thorpej } 1283 1.1 thorpej 1284 1.1 thorpej return (1); 1285 1.1 thorpej } 1286 1.1 thorpej #ifdef INET6 1287 1.1 thorpej else if (front->ff_flow.fi_family == AF_INET6) { 1288 1.1 thorpej struct flow_filter6 *front6, *back6; 1289 1.1 thorpej int i; 1290 1.1 thorpej 1291 1.1 thorpej front6 = (struct flow_filter6 *)front; 1292 1.1 thorpej back6 = (struct flow_filter6 *)back; 1293 1.1 thorpej 1294 1.1 thorpej if (front6->ff_flow6.fi6_proto == 0 && 1295 1.1 thorpej back6->ff_flow6.fi6_proto != 0) 1296 1.1 thorpej return (0); 1297 1.1 thorpej if (front6->ff_flow6.fi6_flowlabel == 0 && 1298 1.1 thorpej back6->ff_flow6.fi6_flowlabel != 0) 1299 1.1 thorpej return (0); 1300 1.1 thorpej if (front6->ff_flow6.fi6_gpi == 0 && 1301 1.1 thorpej back6->ff_flow6.fi6_gpi != 0) 1302 1.1 thorpej return (0); 1303 1.1 thorpej 1304 1.1 thorpej if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src)) { 1305 1.1 thorpej if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 1306 1.1 thorpej return (0); 1307 1.1 thorpej } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 1308 1.1 thorpej for (i=0; i<4; i++) 1309 1.11 christos if (~IN6ADDR32_GET(&front6->ff_mask6.mask6_src, i) & 1310 1.11 christos IN6ADDR32_GET(&back6->ff_mask6.mask6_src, i)) 1311 1.1 thorpej return (0); 1312 1.1 thorpej if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst)) { 1313 1.1 thorpej if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 1314 1.1 thorpej return (0); 1315 1.1 thorpej } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 1316 1.1 thorpej for (i=0; i<4; i++) 1317 1.11 christos if (~IN6ADDR32_GET(&front6->ff_mask6.mask6_dst, i) & 1318 1.11 christos IN6ADDR32_GET(&back6->ff_mask6.mask6_dst, i)) 1319 1.1 thorpej return (0); 1320 1.1 thorpej 1321 1.1 thorpej if (~front6->ff_mask6.mask6_tclass & 1322 1.1 thorpej back6->ff_mask6.mask6_tclass) 1323 1.1 thorpej return (0); 1324 1.1 thorpej 1325 1.1 thorpej if (front6->ff_flow6.fi6_sport == 0 && 1326 1.1 thorpej back6->ff_flow6.fi6_sport != 0) { 1327 1.1 thorpej srcport = ntohs(back6->ff_flow6.fi6_sport); 1328 1.1 thorpej dstport = ntohs(front6->ff_flow6.fi6_dport); 1329 1.1 thorpej if (dstport > 0 /* && dstport < 1024 */ && 1330 1.1 thorpej srcport > 0 /* && srcport < 1024 */) 1331 1.1 thorpej return (2); 1332 1.1 thorpej return (0); 1333 1.1 thorpej } 1334 1.1 thorpej if (front6->ff_flow6.fi6_dport == 0 && 1335 1.1 thorpej back6->ff_flow6.fi6_dport != 0) { 1336 1.1 thorpej dstport = ntohs(back6->ff_flow6.fi6_dport); 1337 1.1 thorpej srcport = ntohs(front6->ff_flow6.fi6_sport); 1338 1.1 thorpej if (srcport > 0 /* && srcport < 1024 */ && 1339 1.1 thorpej dstport > 0 /* && dstport < 1024 */) 1340 1.1 thorpej return (2); 1341 1.1 thorpej return (0); 1342 1.1 thorpej } 1343 1.1 thorpej } 1344 1.1 thorpej #endif /* INET6 */ 1345 1.1 thorpej return (1); 1346 1.1 thorpej } 1347 1.1 thorpej 1348 1.1 thorpej 1349 1.1 thorpej /* 1350 1.1 thorpej * setting RED or RIO default parameters 1351 1.1 thorpej */ 1352 1.1 thorpej int 1353 1.1 thorpej qop_red_set_defaults(int th_min, int th_max, int inv_pmax) 1354 1.1 thorpej { 1355 1.1 thorpej struct redparams params; 1356 1.1 thorpej int fd; 1357 1.1 thorpej 1358 1.1 thorpej if ((fd = open(RED_DEVICE, O_RDWR)) < 0) { 1359 1.4 itojun LOG(LOG_ERR, errno, "RED open"); 1360 1.1 thorpej return (QOPERR_SYSCALL); 1361 1.1 thorpej } 1362 1.1 thorpej 1363 1.1 thorpej params.th_min = th_min; 1364 1.1 thorpej params.th_max = th_max; 1365 1.1 thorpej params.inv_pmax = inv_pmax; 1366 1.1 thorpej 1367 1.1 thorpej if (ioctl(fd, RED_SETDEFAULTS, ¶ms) < 0) { 1368 1.4 itojun LOG(LOG_ERR, errno, "RED_SETDEFAULTS"); 1369 1.10 wiz (void)close(fd); 1370 1.1 thorpej return (QOPERR_SYSCALL); 1371 1.1 thorpej } 1372 1.1 thorpej 1373 1.1 thorpej (void)close(fd); 1374 1.1 thorpej return (0); 1375 1.1 thorpej } 1376 1.1 thorpej 1377 1.1 thorpej int 1378 1.1 thorpej qop_rio_set_defaults(struct redparams *params) 1379 1.1 thorpej { 1380 1.1 thorpej int i, fd; 1381 1.1 thorpej 1382 1.1 thorpej /* sanity check */ 1383 1.1 thorpej for (i = 1; i < RIO_NDROPPREC; i++) { 1384 1.1 thorpej if (params[i].th_max > params[i-1].th_min) 1385 1.1 thorpej LOG(LOG_WARNING, 0, 1386 1.4 itojun "warning: overlap found in RIO thresholds"); 1387 1.1 thorpej } 1388 1.1 thorpej 1389 1.1 thorpej if ((fd = open(RIO_DEVICE, O_RDWR)) < 0) { 1390 1.4 itojun LOG(LOG_ERR, errno, "RIO open"); 1391 1.1 thorpej return (QOPERR_SYSCALL); 1392 1.1 thorpej } 1393 1.1 thorpej 1394 1.1 thorpej if (ioctl(fd, RIO_SETDEFAULTS, params) < 0) { 1395 1.4 itojun LOG(LOG_ERR, errno, "RIO_SETDEFAULTS"); 1396 1.10 wiz (void)close(fd); 1397 1.1 thorpej return (QOPERR_SYSCALL); 1398 1.1 thorpej } 1399 1.1 thorpej 1400 1.1 thorpej (void)close(fd); 1401 1.1 thorpej return (0); 1402 1.1 thorpej } 1403 1.1 thorpej 1404 1.1 thorpej /* 1405 1.1 thorpej * try to load and open KLD module 1406 1.4 itojun * (also check the altq device file) 1407 1.1 thorpej */ 1408 1.1 thorpej int 1409 1.9 xtraeme open_module(const char *dvname, int flags) 1410 1.1 thorpej { 1411 1.1 thorpej #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 1412 1.2 itojun char modname[64], filename[MAXPATHLEN], *cp; 1413 1.1 thorpej int fd; 1414 1.4 itojun #endif 1415 1.1 thorpej struct stat sbuf; 1416 1.1 thorpej 1417 1.4 itojun /* check if the altq device exists */ 1418 1.9 xtraeme if (stat(dvname, &sbuf) < 0) { 1419 1.9 xtraeme LOG(LOG_ERR, errno, "can't access %s!", dvname); 1420 1.4 itojun return (-1); 1421 1.4 itojun } 1422 1.4 itojun 1423 1.4 itojun #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 1424 1.1 thorpej /* turn discipline name into module name */ 1425 1.2 itojun strlcpy(modname, "altq_", sizeof(modname)); 1426 1.1 thorpej if ((cp = strrchr(devname, '/')) == NULL) 1427 1.1 thorpej return (-1); 1428 1.2 itojun strlcat(modname, cp + 1, sizeof(modname)); 1429 1.1 thorpej 1430 1.1 thorpej /* check if the kld module exists */ 1431 1.2 itojun snprintf(filename, sizeof(filename), "/modules/%s.ko", modname); 1432 1.1 thorpej if (stat(filename, &sbuf) < 0) { 1433 1.1 thorpej /* module file doesn't exist */ 1434 1.1 thorpej return (-1); 1435 1.1 thorpej } 1436 1.1 thorpej 1437 1.1 thorpej if (kldload(modname) < 0) { 1438 1.4 itojun LOG(LOG_ERR, errno, "kldload %s failed!", modname); 1439 1.1 thorpej return (-1); 1440 1.1 thorpej } 1441 1.1 thorpej 1442 1.1 thorpej /* successfully loaded, open the device */ 1443 1.4 itojun LOG(LOG_INFO, 0, "kld module %s loaded", modname); 1444 1.1 thorpej fd = open(devname, flags); 1445 1.1 thorpej return (fd); 1446 1.1 thorpej #else 1447 1.1 thorpej return (-1); 1448 1.1 thorpej #endif 1449 1.1 thorpej } 1450