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