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