1*89ff1cb6Sozaki-r /* $NetBSD: qop.c,v 1.13 2024/12/24 08:35:28 ozaki-r Exp $ */ 269881cf6Sitojun /* $KAME: qop.c,v 1.11 2001/10/26 04:57:59 kjc Exp $ */ 395a65560Sthorpej /* 495a65560Sthorpej * Copyright (C) 1999-2000 595a65560Sthorpej * Sony Computer Science Laboratories, Inc. All rights reserved. 695a65560Sthorpej * 795a65560Sthorpej * Redistribution and use in source and binary forms, with or without 895a65560Sthorpej * modification, are permitted provided that the following conditions 995a65560Sthorpej * are met: 1095a65560Sthorpej * 1. Redistributions of source code must retain the above copyright 1195a65560Sthorpej * notice, this list of conditions and the following disclaimer. 1295a65560Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 1395a65560Sthorpej * notice, this list of conditions and the following disclaimer in the 1495a65560Sthorpej * documentation and/or other materials provided with the distribution. 1595a65560Sthorpej * 1695a65560Sthorpej * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 1795a65560Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1895a65560Sthorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1995a65560Sthorpej * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 2095a65560Sthorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2195a65560Sthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2295a65560Sthorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2395a65560Sthorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2495a65560Sthorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2595a65560Sthorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2695a65560Sthorpej * SUCH DAMAGE. 2795a65560Sthorpej */ 2895a65560Sthorpej 2995a65560Sthorpej #include <sys/param.h> 3095a65560Sthorpej #include <sys/socket.h> 3195a65560Sthorpej #include <sys/sockio.h> 3295a65560Sthorpej #include <sys/ioctl.h> 3395a65560Sthorpej #include <sys/fcntl.h> 3495a65560Sthorpej #include <sys/stat.h> 3595a65560Sthorpej #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 3695a65560Sthorpej #include <sys/linker.h> 3795a65560Sthorpej #endif 3895a65560Sthorpej 3995a65560Sthorpej #include <net/if.h> 4095a65560Sthorpej #include <netinet/in.h> 4195a65560Sthorpej #include <arpa/inet.h> 4295a65560Sthorpej #include <stdio.h> 4395a65560Sthorpej #include <stdlib.h> 4495a65560Sthorpej #include <unistd.h> 4595a65560Sthorpej #include <stddef.h> 4695a65560Sthorpej #include <string.h> 4795a65560Sthorpej #include <ctype.h> 4895a65560Sthorpej #include <errno.h> 4995a65560Sthorpej #include <err.h> 5095a65560Sthorpej #include <syslog.h> 5195a65560Sthorpej 5295a65560Sthorpej #include <altq/altq.h> 5395a65560Sthorpej #include <altq/altq_red.h> 5495a65560Sthorpej #include <altq/altq_rio.h> 5595a65560Sthorpej #include <altq/altq_cdnr.h> 5695a65560Sthorpej #include "altq_qop.h" 5795a65560Sthorpej #include "qop_cdnr.h" 5895a65560Sthorpej 5995a65560Sthorpej #define ALTQ_DEVICE "/dev/altq/altq" 6095a65560Sthorpej #define RED_DEVICE "/dev/altq/red" 6195a65560Sthorpej #define RIO_DEVICE "/dev/altq/rio" 6295a65560Sthorpej #define CDNR_DEVICE "/dev/altq/cdnr" 6395a65560Sthorpej 6495a65560Sthorpej #ifndef LIST_HEAD_INITIALIZER 6595a65560Sthorpej #define LIST_HEAD_INITIALIZER(head) { NULL } 6695a65560Sthorpej #endif 6795a65560Sthorpej 6895a65560Sthorpej /* 6995a65560Sthorpej * token bucket regulator information 7095a65560Sthorpej */ 7195a65560Sthorpej struct tbrinfo { 7295a65560Sthorpej LIST_ENTRY(tbrinfo) link; 7395a65560Sthorpej char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */ 7495a65560Sthorpej struct tb_profile tb_prof, otb_prof; 7595a65560Sthorpej int installed; 7695a65560Sthorpej }; 7795a65560Sthorpej 7895a65560Sthorpej /* 7995a65560Sthorpej * Static globals 8095a65560Sthorpej */ 8195a65560Sthorpej /* a list of configured interfaces */ 8295a65560Sthorpej LIST_HEAD(qop_iflist, ifinfo) qop_iflist = LIST_HEAD_INITIALIZER(&iflist); 8395a65560Sthorpej /* a list of configured token bucket regulators */ 8495a65560Sthorpej LIST_HEAD(tbr_list, tbrinfo) tbr_list = LIST_HEAD_INITIALIZER(&tbr_list); 8595a65560Sthorpej 8695a65560Sthorpej /* 8795a65560Sthorpej * internal functions 8895a65560Sthorpej */ 898b8734d2Sitojun static int get_ifmtu(const char *); 908b8734d2Sitojun static void tbr_install(const char *); 918b8734d2Sitojun static void tbr_deinstall(const char *); 928b8734d2Sitojun static int add_filter_rule(struct ifinfo *, struct fltrinfo *, 938b8734d2Sitojun struct fltrinfo **); 948b8734d2Sitojun static int remove_filter_rule(struct ifinfo *, 958b8734d2Sitojun struct fltrinfo *); 968b8734d2Sitojun static int filt_check_relation(struct flow_filter *, struct flow_filter *); 978b8734d2Sitojun static int filt_disjoint(struct flow_filter *, struct flow_filter *); 988b8734d2Sitojun static int filt_subset(struct flow_filter *, struct flow_filter *); 9995a65560Sthorpej 10095a65560Sthorpej /* 10195a65560Sthorpej * QCMD (Queue Command) API 10295a65560Sthorpej */ 10395a65560Sthorpej int 10495a65560Sthorpej qcmd_init(void) 10595a65560Sthorpej { 10695a65560Sthorpej int error; 10795a65560Sthorpej 10895a65560Sthorpej /* read config file and execute commands */ 10995a65560Sthorpej error = qcmd_config(); 11095a65560Sthorpej if (error != 0) 111d5e1f166Sitojun return (error); 112d5e1f166Sitojun 113d5e1f166Sitojun error = qcmd_enableall(); 114d5e1f166Sitojun if (error != 0) 115d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: qcmd_init failed", qoperror(error)); 11695a65560Sthorpej return (error); 11795a65560Sthorpej } 11895a65560Sthorpej 11995a65560Sthorpej int 12095a65560Sthorpej qcmd_enable(const char *ifname) 12195a65560Sthorpej { 12295a65560Sthorpej struct ifinfo *ifinfo; 12395a65560Sthorpej int error = 0; 12495a65560Sthorpej 12595a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 12695a65560Sthorpej error = QOPERR_BADIF; 12795a65560Sthorpej 12895a65560Sthorpej if (error == 0) 12995a65560Sthorpej error = qop_enable(ifinfo); 13095a65560Sthorpej 13195a65560Sthorpej if (error == 0) { 132d5e1f166Sitojun LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)", 13395a65560Sthorpej ifinfo->qdisc->qname, ifname, ifinfo->ifmtu); 13495a65560Sthorpej } else 135d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: enable failed!", qoperror(error)); 13695a65560Sthorpej return (error); 13795a65560Sthorpej } 13895a65560Sthorpej 13995a65560Sthorpej int 14095a65560Sthorpej qcmd_disable(const char *ifname) 14195a65560Sthorpej { 14295a65560Sthorpej struct ifinfo *ifinfo; 14395a65560Sthorpej int error = 0; 14495a65560Sthorpej 14595a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 14695a65560Sthorpej error = QOPERR_BADIF; 14795a65560Sthorpej 14895a65560Sthorpej if (error == 0) 14995a65560Sthorpej error = qop_disable(ifinfo); 15095a65560Sthorpej 15195a65560Sthorpej if (error != 0) 152d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: disable failed!", qoperror(error)); 15395a65560Sthorpej return (error); 15495a65560Sthorpej } 15595a65560Sthorpej 15695a65560Sthorpej int 15795a65560Sthorpej qcmd_enableall() 15895a65560Sthorpej { 15995a65560Sthorpej struct ifinfo *ifinfo; 16095a65560Sthorpej int error; 16195a65560Sthorpej 16295a65560Sthorpej LIST_FOREACH(ifinfo, &qop_iflist, next) { 16395a65560Sthorpej if ((error = qop_enable(ifinfo)) != 0) 16495a65560Sthorpej return (error); 165d5e1f166Sitojun LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)", 16695a65560Sthorpej ifinfo->qdisc->qname, ifinfo->ifname, ifinfo->ifmtu); 16795a65560Sthorpej } 16895a65560Sthorpej return (0); 16995a65560Sthorpej } 17095a65560Sthorpej 17195a65560Sthorpej int 17295a65560Sthorpej qcmd_disableall() 17395a65560Sthorpej { 17495a65560Sthorpej struct ifinfo *ifinfo; 1757097d2c1Sxtraeme int lerr, error = 0; 17695a65560Sthorpej 17795a65560Sthorpej LIST_FOREACH(ifinfo, &qop_iflist, next) 1787097d2c1Sxtraeme if ((lerr = qop_disable(ifinfo)) != 0) 17995a65560Sthorpej if (error == 0) 1807097d2c1Sxtraeme error = lerr; 18195a65560Sthorpej return (error); 18295a65560Sthorpej } 18395a65560Sthorpej 18495a65560Sthorpej int 18595a65560Sthorpej qcmd_clear(const char *ifname) 18695a65560Sthorpej { 18795a65560Sthorpej struct ifinfo *ifinfo; 18895a65560Sthorpej int error = 0; 18995a65560Sthorpej 19095a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 19195a65560Sthorpej error = QOPERR_BADIF; 19295a65560Sthorpej 19395a65560Sthorpej if (error == 0) 19495a65560Sthorpej error = qop_clear(ifinfo); 19595a65560Sthorpej if (error != 0) 196d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: clear failed!", qoperror(error)); 19795a65560Sthorpej return (error); 19895a65560Sthorpej } 19995a65560Sthorpej 20095a65560Sthorpej int 20195a65560Sthorpej qcmd_destroyall(void) 20295a65560Sthorpej { 20395a65560Sthorpej while (!LIST_EMPTY(&qop_iflist)) 20495a65560Sthorpej (void)qop_delete_if(LIST_FIRST(&qop_iflist)); 20595a65560Sthorpej return (0); 20695a65560Sthorpej } 20795a65560Sthorpej 20895a65560Sthorpej int 20995a65560Sthorpej qcmd_restart(void) 21095a65560Sthorpej { 21195a65560Sthorpej qcmd_destroyall(); 21295a65560Sthorpej return qcmd_init(); 21395a65560Sthorpej } 21495a65560Sthorpej 21595a65560Sthorpej int 21695a65560Sthorpej qcmd_delete_class(const char *ifname, const char *clname) 21795a65560Sthorpej { 21895a65560Sthorpej struct ifinfo *ifinfo; 2197cc15c30She struct classinfo *clinfo = NULL; 22095a65560Sthorpej int error = 0; 22195a65560Sthorpej 22295a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 22395a65560Sthorpej error = QOPERR_BADIF; 22495a65560Sthorpej 22595a65560Sthorpej if (error == 0 && 22695a65560Sthorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 22795a65560Sthorpej error = QOPERR_BADCLASS; 22895a65560Sthorpej 22995a65560Sthorpej if (error == 0) 23095a65560Sthorpej error = qop_delete_class(clinfo); 23195a65560Sthorpej if (error != 0) 232d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: delete_class failed", 23395a65560Sthorpej qoperror(error)); 23495a65560Sthorpej return (error); 23595a65560Sthorpej } 23695a65560Sthorpej 23795a65560Sthorpej int 23895a65560Sthorpej qcmd_add_filter(const char *ifname, const char *clname, const char *flname, 23995a65560Sthorpej const struct flow_filter *fltr) 24095a65560Sthorpej { 24195a65560Sthorpej struct ifinfo *ifinfo; 2427cc15c30She struct classinfo *clinfo = NULL; 24395a65560Sthorpej int error = 0; 24495a65560Sthorpej 24595a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 24695a65560Sthorpej error = QOPERR_BADIF; 24795a65560Sthorpej 24895a65560Sthorpej if (error == 0 && 24995a65560Sthorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) { 25095a65560Sthorpej /* 25195a65560Sthorpej * there is no matching class. 25295a65560Sthorpej * check if it is for a traffic conditioner 25395a65560Sthorpej */ 25495a65560Sthorpej if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL || 25595a65560Sthorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 25695a65560Sthorpej error = QOPERR_BADCLASS; 25795a65560Sthorpej } 25895a65560Sthorpej 25995a65560Sthorpej if (error == 0) 26095a65560Sthorpej error = qop_add_filter(NULL, clinfo, flname, fltr, NULL); 26195a65560Sthorpej 26295a65560Sthorpej if (error != 0) 263d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: add filter failed!", 26495a65560Sthorpej qoperror(error)); 26595a65560Sthorpej else if (IsDebug(DEBUG_ALTQ)) { 266d5e1f166Sitojun LOG(LOG_DEBUG, 0, "%s: add a filter %s to class %s", 26795a65560Sthorpej ifname, flname ? flname : "(null)", 26895a65560Sthorpej clname ? clname : "(null)"); 26995a65560Sthorpej print_filter(fltr); 27095a65560Sthorpej } 27195a65560Sthorpej return (error); 27295a65560Sthorpej } 27395a65560Sthorpej 27495a65560Sthorpej int 27595a65560Sthorpej qcmd_delete_filter(const char *ifname, const char *clname, const char *flname) 27695a65560Sthorpej { 27795a65560Sthorpej struct ifinfo *ifinfo; 2787cc15c30She struct classinfo *clinfo = NULL; 2797cc15c30She struct fltrinfo *fltrinfo = NULL; 28095a65560Sthorpej int error = 0; 28195a65560Sthorpej 28295a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 28395a65560Sthorpej error = QOPERR_BADIF; 28495a65560Sthorpej 28595a65560Sthorpej if (error == 0 && 28695a65560Sthorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) { 28795a65560Sthorpej /* 28895a65560Sthorpej * there is no matching class. 28995a65560Sthorpej * check if it is for a traffic conditioner 29095a65560Sthorpej */ 29195a65560Sthorpej if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL || 29295a65560Sthorpej (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 29395a65560Sthorpej error = QOPERR_BADCLASS; 29495a65560Sthorpej } 29595a65560Sthorpej 29695a65560Sthorpej if (error == 0 && 29795a65560Sthorpej (fltrinfo = flname2flinfo(clinfo, flname)) == NULL) 29895a65560Sthorpej error = QOPERR_BADFILTER; 29995a65560Sthorpej 30095a65560Sthorpej if (error == 0) 30195a65560Sthorpej error = qop_delete_filter(fltrinfo); 30295a65560Sthorpej if (error != 0) 303d5e1f166Sitojun LOG(LOG_ERR, errno, "%s: delete filter failed!", 30495a65560Sthorpej qoperror(error)); 30595a65560Sthorpej return (error); 30695a65560Sthorpej } 30795a65560Sthorpej 30895a65560Sthorpej int 309*89ff1cb6Sozaki-r qcmd_tbr_register(const char *ifname, uint64_t rate, u_int size) 31095a65560Sthorpej { 31195a65560Sthorpej struct tbrinfo *info; 31295a65560Sthorpej 31395a65560Sthorpej if ((info = calloc(1, sizeof(struct tbrinfo))) == NULL) 31495a65560Sthorpej return (QOPERR_NOMEM); 31595a65560Sthorpej 3168b8734d2Sitojun strlcpy(info->ifname, ifname, sizeof(info->ifname)); 31795a65560Sthorpej info->tb_prof.rate = rate; 31895a65560Sthorpej info->tb_prof.depth = size; 31995a65560Sthorpej info->installed = 0; 32095a65560Sthorpej LIST_INSERT_HEAD(&tbr_list, info, link); 32195a65560Sthorpej return (0); 32295a65560Sthorpej } 32395a65560Sthorpej 32495a65560Sthorpej /* 32595a65560Sthorpej * QOP (Queue Operation) API 32695a65560Sthorpej */ 32795a65560Sthorpej 32895a65560Sthorpej int 329*89ff1cb6Sozaki-r qop_add_if(struct ifinfo **rp, const char *ifname, uint64_t bandwidth, 33095a65560Sthorpej struct qdisc_ops *qdisc_ops, void *if_private) 33195a65560Sthorpej { 33295a65560Sthorpej struct ifinfo *ifinfo; 33395a65560Sthorpej int error; 33495a65560Sthorpej 33595a65560Sthorpej if (ifname2ifinfo(ifname) != NULL) { 336d5e1f166Sitojun LOG(LOG_ERR, 0, "qop_add_if: %s already exists!", ifname); 33795a65560Sthorpej return (QOPERR_BADIF); 33895a65560Sthorpej } 33995a65560Sthorpej 34095a65560Sthorpej if ((ifinfo = calloc(1, sizeof(struct ifinfo))) == NULL) 34195a65560Sthorpej return (QOPERR_NOMEM); 34295a65560Sthorpej ifinfo->ifname = strdup(ifname); 34395a65560Sthorpej ifinfo->bandwidth = bandwidth; 34495a65560Sthorpej ifinfo->enabled = 0; 34595a65560Sthorpej if (ifname[0] == '_') 34695a65560Sthorpej /* input interface */ 34795a65560Sthorpej ifname += 1; 34895a65560Sthorpej ifinfo->ifindex = get_ifindex(ifname); 34995a65560Sthorpej ifinfo->ifmtu = get_ifmtu(ifname); 35091c703aeSpeter if (qdisc_ops == NULL) 35195a65560Sthorpej ifinfo->qdisc = &nop_qdisc; /* replace syscalls by nops */ 35295a65560Sthorpej else 35395a65560Sthorpej ifinfo->qdisc = qdisc_ops; 35495a65560Sthorpej ifinfo->private = if_private; 35595a65560Sthorpej LIST_INIT(&ifinfo->cllist); 35695a65560Sthorpej LIST_INIT(&ifinfo->fltr_rules); 35795a65560Sthorpej 35895a65560Sthorpej /* Link the interface info structure */ 35995a65560Sthorpej LIST_INSERT_HEAD(&qop_iflist, ifinfo, next); 36095a65560Sthorpej 36195a65560Sthorpej /* install token bucket regulator, if necessary */ 36295a65560Sthorpej tbr_install(ifname); 36395a65560Sthorpej 36495a65560Sthorpej /* attach the discipline to the interface */ 36595a65560Sthorpej if ((error = (*ifinfo->qdisc->attach)(ifinfo)) != 0) 36695a65560Sthorpej goto err_ret; 36795a65560Sthorpej 36895a65560Sthorpej /* disable and clear the interface */ 36995a65560Sthorpej if (ifinfo->qdisc->disable != NULL) 37095a65560Sthorpej if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0) 37195a65560Sthorpej goto err_ret; 37295a65560Sthorpej if (ifinfo->qdisc->clear != NULL) 37395a65560Sthorpej if ((error = (*ifinfo->qdisc->clear)(ifinfo)) != 0) 37495a65560Sthorpej goto err_ret; 37595a65560Sthorpej 37695a65560Sthorpej if (rp != NULL) 37795a65560Sthorpej *rp = ifinfo; 37895a65560Sthorpej return (0); 37995a65560Sthorpej 38095a65560Sthorpej err_ret: 38195a65560Sthorpej if (ifinfo != NULL) { 38295a65560Sthorpej LIST_REMOVE(ifinfo, next); 38395a65560Sthorpej if (ifinfo->ifname != NULL) 38495a65560Sthorpej free(ifinfo->ifname); 38595a65560Sthorpej free(ifinfo); 38695a65560Sthorpej } 38795a65560Sthorpej return (error); 38895a65560Sthorpej } 38995a65560Sthorpej 39095a65560Sthorpej int 39195a65560Sthorpej qop_delete_if(struct ifinfo *ifinfo) 39295a65560Sthorpej { 39395a65560Sthorpej (void)qop_disable(ifinfo); 39495a65560Sthorpej (void)qop_clear(ifinfo); 39595a65560Sthorpej 39695a65560Sthorpej if (ifinfo->delete_hook != NULL) 39795a65560Sthorpej (*ifinfo->delete_hook)(ifinfo); 39895a65560Sthorpej 39995a65560Sthorpej /* remove this entry from qop_iflist */ 40095a65560Sthorpej LIST_REMOVE(ifinfo, next); 40195a65560Sthorpej 40295a65560Sthorpej (void)(*ifinfo->qdisc->detach)(ifinfo); 40395a65560Sthorpej 40495a65560Sthorpej /* deinstall token bucket regulator, if necessary */ 40595a65560Sthorpej tbr_deinstall(ifinfo->ifname); 40695a65560Sthorpej 40795a65560Sthorpej if (ifinfo->private != NULL) 40895a65560Sthorpej free(ifinfo->private); 40995a65560Sthorpej if (ifinfo->ifname != NULL) 41095a65560Sthorpej free(ifinfo->ifname); 41195a65560Sthorpej free(ifinfo); 41295a65560Sthorpej return (0); 41395a65560Sthorpej } 41495a65560Sthorpej 41595a65560Sthorpej int 41695a65560Sthorpej qop_enable(struct ifinfo *ifinfo) 41795a65560Sthorpej { 41895a65560Sthorpej int error; 41995a65560Sthorpej 42095a65560Sthorpej if (ifinfo->enable_hook != NULL) 42195a65560Sthorpej if ((error = (*ifinfo->enable_hook)(ifinfo)) != 0) 42295a65560Sthorpej return (error); 42395a65560Sthorpej 42495a65560Sthorpej if (ifinfo->qdisc->enable != NULL) 42595a65560Sthorpej if ((error = (*ifinfo->qdisc->enable)(ifinfo)) != 0) 42695a65560Sthorpej return (error); 42795a65560Sthorpej ifinfo->enabled = 1; 42895a65560Sthorpej return (0); 42995a65560Sthorpej } 43095a65560Sthorpej 43195a65560Sthorpej int 43295a65560Sthorpej qop_disable(struct ifinfo *ifinfo) 43395a65560Sthorpej { 43495a65560Sthorpej int error; 43595a65560Sthorpej 43695a65560Sthorpej if (ifinfo->qdisc->disable != NULL) 43795a65560Sthorpej if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0) 43895a65560Sthorpej return (error); 43995a65560Sthorpej ifinfo->enabled = 0; 44095a65560Sthorpej return (0); 44195a65560Sthorpej } 44295a65560Sthorpej 44395a65560Sthorpej int 44495a65560Sthorpej qop_clear(struct ifinfo *ifinfo) 44595a65560Sthorpej { 44695a65560Sthorpej struct classinfo *clinfo; 44795a65560Sthorpej 44895a65560Sthorpej /* free all classes and filters */ 44995a65560Sthorpej if (ifinfo->ifname[0] != '_') { 45095a65560Sthorpej /* output interface. delete from leaf classes */ 45195a65560Sthorpej while (!LIST_EMPTY(&ifinfo->cllist)) { 45295a65560Sthorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) { 45395a65560Sthorpej if (clinfo->child != NULL) 45495a65560Sthorpej continue; 45595a65560Sthorpej qop_delete_class(clinfo); 45695a65560Sthorpej /* 45795a65560Sthorpej * the list has been changed, 45895a65560Sthorpej * restart from the head 45995a65560Sthorpej */ 46095a65560Sthorpej break; 46195a65560Sthorpej } 46295a65560Sthorpej } 46395a65560Sthorpej } else { 46495a65560Sthorpej /* input interface. delete from parents */ 46595a65560Sthorpej struct classinfo *root = get_rootclass(ifinfo); 46695a65560Sthorpej 46795a65560Sthorpej while (!LIST_EMPTY(&ifinfo->cllist)) { 46895a65560Sthorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 46995a65560Sthorpej if (clinfo->parent == root) { 47095a65560Sthorpej qop_delete_cdnr(clinfo); 47195a65560Sthorpej break; 47295a65560Sthorpej } 473e02941daSchristos if (root->child != NULL) 47495a65560Sthorpej qop_delete_class(root); 47595a65560Sthorpej } 47695a65560Sthorpej } 47795a65560Sthorpej 47895a65560Sthorpej /* clear the interface */ 47995a65560Sthorpej if (ifinfo->qdisc->clear != NULL) 48095a65560Sthorpej return (*ifinfo->qdisc->clear)(ifinfo); 48195a65560Sthorpej return (0); 48295a65560Sthorpej } 48395a65560Sthorpej 48495a65560Sthorpej int 48595a65560Sthorpej qop_add_class(struct classinfo **rp, const char *clname, 48695a65560Sthorpej struct ifinfo *ifinfo, struct classinfo *parent, 48795a65560Sthorpej void *class_private) 48895a65560Sthorpej { 48995a65560Sthorpej struct classinfo *clinfo; 49095a65560Sthorpej int error; 49195a65560Sthorpej 49295a65560Sthorpej if ((clinfo = calloc(1, sizeof(*clinfo))) == NULL) 49395a65560Sthorpej return (QOPERR_NOMEM); 49495a65560Sthorpej 49595a65560Sthorpej if (clname != NULL) 49695a65560Sthorpej clinfo->clname = strdup(clname); 49795a65560Sthorpej else 49895a65560Sthorpej clinfo->clname = strdup("(null)"); /* dummy name */ 49995a65560Sthorpej clinfo->ifinfo = ifinfo; 50095a65560Sthorpej clinfo->private = class_private; 50195a65560Sthorpej clinfo->parent = parent; 50295a65560Sthorpej clinfo->child = NULL; 50395a65560Sthorpej LIST_INIT(&clinfo->fltrlist); 50495a65560Sthorpej 50595a65560Sthorpej if ((error = (*ifinfo->qdisc->add_class)(clinfo)) != 0) 50695a65560Sthorpej goto err_ret; 50795a65560Sthorpej 50895a65560Sthorpej /* link classinfo in lists */ 50995a65560Sthorpej LIST_INSERT_HEAD(&ifinfo->cllist, clinfo, next); 51095a65560Sthorpej 51195a65560Sthorpej if (parent != NULL) { 51295a65560Sthorpej clinfo->sibling = parent->child; 51395a65560Sthorpej clinfo->parent->child = clinfo; 51495a65560Sthorpej } 51595a65560Sthorpej 51695a65560Sthorpej if (rp != NULL) 51795a65560Sthorpej *rp = clinfo; 51895a65560Sthorpej return (0); 51995a65560Sthorpej 52095a65560Sthorpej err_ret: 52195a65560Sthorpej if (clinfo != NULL) { 52295a65560Sthorpej if (clinfo->clname != NULL) 52395a65560Sthorpej free(clinfo->clname); 52495a65560Sthorpej free(clinfo); 52595a65560Sthorpej } 52695a65560Sthorpej return (error); 52795a65560Sthorpej } 52895a65560Sthorpej 52995a65560Sthorpej int 53095a65560Sthorpej qop_modify_class(struct classinfo *clinfo, void *arg) 53195a65560Sthorpej { 53295a65560Sthorpej return (*clinfo->ifinfo->qdisc->modify_class)(clinfo, arg); 53395a65560Sthorpej } 53495a65560Sthorpej 53595a65560Sthorpej int 53695a65560Sthorpej qop_delete_class(struct classinfo *clinfo) 53795a65560Sthorpej { 53895a65560Sthorpej struct ifinfo *ifinfo = clinfo->ifinfo; 53995a65560Sthorpej struct classinfo *prev; 54095a65560Sthorpej int error; 54195a65560Sthorpej 54295a65560Sthorpej /* a class to be removed should not have a child */ 54395a65560Sthorpej if (clinfo->child != NULL) 54495a65560Sthorpej return (QOPERR_CLASS_PERM); 54595a65560Sthorpej 54695a65560Sthorpej /* remove filters associated to this class */ 54795a65560Sthorpej while (!LIST_EMPTY(&clinfo->fltrlist)) 54895a65560Sthorpej (void)qop_delete_filter(LIST_FIRST(&clinfo->fltrlist)); 54995a65560Sthorpej 55095a65560Sthorpej if (clinfo->delete_hook != NULL) 55195a65560Sthorpej (*clinfo->delete_hook)(clinfo); 55295a65560Sthorpej 55395a65560Sthorpej /* remove class info from the interface */ 55495a65560Sthorpej LIST_REMOVE(clinfo, next); 55595a65560Sthorpej 55695a65560Sthorpej /* remove this class from the child list */ 55795a65560Sthorpej if (clinfo->parent != NULL) { 55895a65560Sthorpej if (clinfo->parent->child == clinfo) 55995a65560Sthorpej clinfo->parent->child = clinfo->sibling; 56095a65560Sthorpej else for (prev = clinfo->parent->child; prev->sibling != NULL; 56195a65560Sthorpej prev = prev->sibling) 56295a65560Sthorpej if (prev->sibling == clinfo) { 56395a65560Sthorpej prev->sibling = clinfo->sibling; 56495a65560Sthorpej break; 56595a65560Sthorpej } 56695a65560Sthorpej } 56795a65560Sthorpej 56895a65560Sthorpej /* delete class from kernel */ 56995a65560Sthorpej if ((error = (*ifinfo->qdisc->delete_class)(clinfo)) != 0) 57095a65560Sthorpej return (error); 57195a65560Sthorpej 57295a65560Sthorpej if (clinfo->private != NULL) 57395a65560Sthorpej free(clinfo->private); 57495a65560Sthorpej if (clinfo->clname != NULL) 57595a65560Sthorpej free(clinfo->clname); 57695a65560Sthorpej free(clinfo); 57795a65560Sthorpej return (0); 57895a65560Sthorpej } 57995a65560Sthorpej 58095a65560Sthorpej int 58195a65560Sthorpej qop_add_filter(struct fltrinfo **rp, struct classinfo *clinfo, 58295a65560Sthorpej const char *flname, const struct flow_filter *fltr, 58395a65560Sthorpej struct fltrinfo **conflict) 58495a65560Sthorpej { 58595a65560Sthorpej struct ifinfo *ifinfo; 58695a65560Sthorpej struct fltrinfo *fltrinfo; 58795a65560Sthorpej int error; 58895a65560Sthorpej 58995a65560Sthorpej if ((fltrinfo = calloc(1, sizeof(*fltrinfo))) == NULL) 59095a65560Sthorpej return (QOPERR_NOMEM); 59195a65560Sthorpej 59295a65560Sthorpej fltrinfo->clinfo = clinfo; 59395a65560Sthorpej fltrinfo->fltr = *fltr; 59495a65560Sthorpej #if 1 59595a65560Sthorpej /* fix this */ 59695a65560Sthorpej fltrinfo->line_no = line_no; /* XXX */ 59795a65560Sthorpej fltrinfo->dontwarn = filter_dontwarn; /* XXX */ 59895a65560Sthorpej #endif 59995a65560Sthorpej if (flname != NULL) 60095a65560Sthorpej fltrinfo->flname = strdup(flname); 60195a65560Sthorpej else 60295a65560Sthorpej fltrinfo->flname = strdup("(null)"); /* dummy name */ 60395a65560Sthorpej 60495a65560Sthorpej /* check and save the filter */ 60595a65560Sthorpej ifinfo = clinfo->ifinfo; 60695a65560Sthorpej if ((error = add_filter_rule(ifinfo, fltrinfo, conflict)) != 0) 60795a65560Sthorpej goto err_ret; 60895a65560Sthorpej 60995a65560Sthorpej /* install the filter to the kernel */ 61095a65560Sthorpej if ((error = (*ifinfo->qdisc->add_filter)(fltrinfo)) != 0) { 61195a65560Sthorpej remove_filter_rule(ifinfo, fltrinfo); 61295a65560Sthorpej goto err_ret; 61395a65560Sthorpej } 61495a65560Sthorpej 61595a65560Sthorpej /* link fltrinfo onto fltrlist of the class */ 61695a65560Sthorpej LIST_INSERT_HEAD(&clinfo->fltrlist, fltrinfo, next); 61795a65560Sthorpej 61895a65560Sthorpej if (rp != NULL) 61995a65560Sthorpej *rp = fltrinfo; 62095a65560Sthorpej return (0); 62195a65560Sthorpej 62295a65560Sthorpej err_ret: 62395a65560Sthorpej if (fltrinfo != NULL) { 62495a65560Sthorpej if (fltrinfo->flname != NULL) 62595a65560Sthorpej free(fltrinfo->flname); 62695a65560Sthorpej free(fltrinfo); 62795a65560Sthorpej } 62895a65560Sthorpej return (error); 62995a65560Sthorpej } 63095a65560Sthorpej 63195a65560Sthorpej int 63295a65560Sthorpej qop_delete_filter(struct fltrinfo *fltrinfo) 63395a65560Sthorpej { 63495a65560Sthorpej struct ifinfo *ifinfo; 63595a65560Sthorpej struct classinfo *clinfo; 63695a65560Sthorpej int error; 63795a65560Sthorpej 63895a65560Sthorpej /* remove filter info from the class */ 63995a65560Sthorpej clinfo = fltrinfo->clinfo; 64095a65560Sthorpej ifinfo = clinfo->ifinfo; 64195a65560Sthorpej 64295a65560Sthorpej 64395a65560Sthorpej /* remove the entry from fltrlist of the class */ 64495a65560Sthorpej LIST_REMOVE(fltrinfo, next); 64595a65560Sthorpej 64695a65560Sthorpej remove_filter_rule(ifinfo, fltrinfo); 64795a65560Sthorpej 64895a65560Sthorpej /* delete filter from kernel */ 64995a65560Sthorpej if ((error = (*ifinfo->qdisc->delete_filter)(fltrinfo)) != 0) 65095a65560Sthorpej return (error); 65195a65560Sthorpej 65295a65560Sthorpej if (fltrinfo->flname) 65395a65560Sthorpej free(fltrinfo->flname); 65495a65560Sthorpej free(fltrinfo); 65595a65560Sthorpej return (0); 65695a65560Sthorpej } 65795a65560Sthorpej 65895a65560Sthorpej const char * 65995a65560Sthorpej qoperror(int qoperrno) 66095a65560Sthorpej { 66195a65560Sthorpej static char buf[64]; 66295a65560Sthorpej 66395a65560Sthorpej if (qoperrno <= QOPERR_MAX) 66495a65560Sthorpej return (qop_errlist[qoperrno]); 6658b8734d2Sitojun snprintf(buf, sizeof(buf), "unknown error %d", qoperrno); 66695a65560Sthorpej return (buf); 66795a65560Sthorpej } 66895a65560Sthorpej 66995a65560Sthorpej /* 67095a65560Sthorpej * misc functions 67195a65560Sthorpej */ 67295a65560Sthorpej struct ifinfo * 67395a65560Sthorpej ifname2ifinfo(const char *ifname) 67495a65560Sthorpej { 67595a65560Sthorpej struct ifinfo *ifinfo; 67695a65560Sthorpej 67795a65560Sthorpej LIST_FOREACH(ifinfo, &qop_iflist, next) 67895a65560Sthorpej if (ifinfo->ifname != NULL && 67995a65560Sthorpej strcmp(ifinfo->ifname, ifname) == 0) 68095a65560Sthorpej return (ifinfo); 68195a65560Sthorpej return (NULL); 68295a65560Sthorpej } 68395a65560Sthorpej 68495a65560Sthorpej struct ifinfo * 68595a65560Sthorpej input_ifname2ifinfo(const char *ifname) 68695a65560Sthorpej { 68795a65560Sthorpej struct ifinfo *ifinfo; 68895a65560Sthorpej 68995a65560Sthorpej LIST_FOREACH(ifinfo, &qop_iflist, next) 69095a65560Sthorpej if (ifinfo->ifname[0] == '_' && 69195a65560Sthorpej strcmp(ifinfo->ifname+1, ifname) == 0) 69295a65560Sthorpej return (ifinfo); 69395a65560Sthorpej return (NULL); 69495a65560Sthorpej } 69595a65560Sthorpej 69695a65560Sthorpej struct classinfo * 69795a65560Sthorpej clname2clinfo(const struct ifinfo *ifinfo, const char *clname) 69895a65560Sthorpej { 69995a65560Sthorpej struct classinfo *clinfo; 70095a65560Sthorpej 70195a65560Sthorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 70295a65560Sthorpej if (clinfo->clname != NULL && 70395a65560Sthorpej strcmp(clinfo->clname, clname) == 0) 70495a65560Sthorpej return (clinfo); 70595a65560Sthorpej return (NULL); 70695a65560Sthorpej } 70795a65560Sthorpej 70895a65560Sthorpej struct classinfo * 70995a65560Sthorpej clhandle2clinfo(struct ifinfo *ifinfo, u_long handle) 71095a65560Sthorpej { 71195a65560Sthorpej struct classinfo *clinfo; 71295a65560Sthorpej 71395a65560Sthorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 71495a65560Sthorpej if (clinfo->handle == handle) 71595a65560Sthorpej return (clinfo); 71695a65560Sthorpej return (NULL); 71795a65560Sthorpej } 71895a65560Sthorpej 71995a65560Sthorpej struct fltrinfo * 72095a65560Sthorpej flname2flinfo(const struct classinfo *clinfo, const char *flname) 72195a65560Sthorpej { 72295a65560Sthorpej struct fltrinfo *fltrinfo; 72395a65560Sthorpej 72495a65560Sthorpej LIST_FOREACH(fltrinfo, &clinfo->fltrlist, next) 72595a65560Sthorpej if (fltrinfo->flname != NULL && 72695a65560Sthorpej strcmp(fltrinfo->flname, flname) == 0) 72795a65560Sthorpej return (fltrinfo); 72895a65560Sthorpej return (NULL); 72995a65560Sthorpej } 73095a65560Sthorpej 73195a65560Sthorpej struct fltrinfo * 73295a65560Sthorpej flhandle2fltrinfo(struct ifinfo *ifinfo, u_long handle) 73395a65560Sthorpej { 73495a65560Sthorpej struct fltrinfo *fltrinfo; 73595a65560Sthorpej 73695a65560Sthorpej LIST_FOREACH(fltrinfo, &ifinfo->fltr_rules, nextrule) 73795a65560Sthorpej if (fltrinfo->handle == handle) 73895a65560Sthorpej return (fltrinfo); 73995a65560Sthorpej return (NULL); 74095a65560Sthorpej } 74195a65560Sthorpej 74295a65560Sthorpej int 74395a65560Sthorpej is_q_enabled(const char *ifname) 74495a65560Sthorpej { 74595a65560Sthorpej struct ifinfo *ifinfo; 74695a65560Sthorpej 74795a65560Sthorpej if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 74895a65560Sthorpej return (0); 74995a65560Sthorpej return (ifinfo->enabled); 75095a65560Sthorpej } 75195a65560Sthorpej 75295a65560Sthorpej /* 75395a65560Sthorpej * functions to walk through a class tree: 75495a65560Sthorpej * 75595a65560Sthorpej * for (clinfo = get_rootclass(ifinfo); 75695a65560Sthorpej * clinfo != NULL; clinfo = get_nextclass(clinfo)) { 75795a65560Sthorpej * do_something; 75895a65560Sthorpej * } 75995a65560Sthorpej */ 76095a65560Sthorpej struct classinfo *get_rootclass(struct ifinfo *ifinfo) 76195a65560Sthorpej { 76295a65560Sthorpej struct classinfo *clinfo; 76395a65560Sthorpej 76495a65560Sthorpej /* find a class without parent */ 76595a65560Sthorpej LIST_FOREACH(clinfo, &ifinfo->cllist, next) 76695a65560Sthorpej if (clinfo->parent == NULL) 76795a65560Sthorpej return (clinfo); 76895a65560Sthorpej return (NULL); 76995a65560Sthorpej } 77095a65560Sthorpej 77195a65560Sthorpej /* return next class in the tree */ 77295a65560Sthorpej struct classinfo *get_nextclass(struct classinfo *clinfo) 77395a65560Sthorpej { 77495a65560Sthorpej struct classinfo *next; 77595a65560Sthorpej 77695a65560Sthorpej if (clinfo->child != NULL) 77795a65560Sthorpej next = clinfo->child; 77895a65560Sthorpej else if (clinfo->sibling != NULL) 77995a65560Sthorpej next = clinfo->sibling; 78095a65560Sthorpej else { 78195a65560Sthorpej next = clinfo; 78295a65560Sthorpej while ((next = next->parent) != NULL) 78395a65560Sthorpej if (next->sibling) { 78495a65560Sthorpej next = next->sibling; 78595a65560Sthorpej break; 78695a65560Sthorpej } 78795a65560Sthorpej } 78895a65560Sthorpej return (next); 78995a65560Sthorpej } 79095a65560Sthorpej 791*89ff1cb6Sozaki-r uint64_t 79295a65560Sthorpej atobps(const char *s) 79395a65560Sthorpej { 79469881cf6Sitojun double bandwidth; 79595a65560Sthorpej char *cp; 79695a65560Sthorpej 79769881cf6Sitojun bandwidth = strtod(s, &cp); 79895a65560Sthorpej if (cp != NULL) { 79995a65560Sthorpej if (*cp == 'K' || *cp == 'k') 80095a65560Sthorpej bandwidth *= 1000; 80195a65560Sthorpej else if (*cp == 'M' || *cp == 'm') 80295a65560Sthorpej bandwidth *= 1000000; 80395a65560Sthorpej else if (*cp == 'G' || *cp == 'g') 80495a65560Sthorpej bandwidth *= 1000000000; 80595a65560Sthorpej } 80669881cf6Sitojun if (bandwidth < 0) 80769881cf6Sitojun bandwidth = 0; 808*89ff1cb6Sozaki-r return ((uint64_t)bandwidth); 80995a65560Sthorpej } 81095a65560Sthorpej 81195a65560Sthorpej u_long 81295a65560Sthorpej atobytes(const char *s) 81395a65560Sthorpej { 81469881cf6Sitojun double bytes; 81595a65560Sthorpej char *cp; 81695a65560Sthorpej 81769881cf6Sitojun bytes = strtod(s, &cp); 81895a65560Sthorpej if (cp != NULL) { 81995a65560Sthorpej if (*cp == 'K' || *cp == 'k') 82095a65560Sthorpej bytes *= 1024; 82195a65560Sthorpej else if (*cp == 'M' || *cp == 'm') 82295a65560Sthorpej bytes *= 1024 * 1024; 82395a65560Sthorpej else if (*cp == 'G' || *cp == 'g') 82495a65560Sthorpej bytes *= 1024 * 1024 * 1024; 82595a65560Sthorpej } 82669881cf6Sitojun if (bytes < 0) 82769881cf6Sitojun bytes = 0; 82869881cf6Sitojun return ((u_long)bytes); 82995a65560Sthorpej } 83095a65560Sthorpej 83195a65560Sthorpej static int 83295a65560Sthorpej get_ifmtu(const char *ifname) 83395a65560Sthorpej { 83495a65560Sthorpej int s, mtu; 83595a65560Sthorpej struct ifreq ifr; 83695a65560Sthorpej #ifdef __OpenBSD__ 83795a65560Sthorpej struct if_data ifdata; 83895a65560Sthorpej #endif 83995a65560Sthorpej 84095a65560Sthorpej mtu = 512; /* default MTU */ 84195a65560Sthorpej 84295a65560Sthorpej if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 84395a65560Sthorpej return (mtu); 84495a65560Sthorpej strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 84595a65560Sthorpej #ifdef __OpenBSD__ 84695a65560Sthorpej ifr.ifr_data = (caddr_t)&ifdata; 84795a65560Sthorpej if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0) 84895a65560Sthorpej mtu = ifdata.ifi_mtu; 84995a65560Sthorpej #else 85095a65560Sthorpej if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) 85195a65560Sthorpej mtu = ifr.ifr_mtu; 85295a65560Sthorpej #endif 85395a65560Sthorpej close(s); 85495a65560Sthorpej return (mtu); 85595a65560Sthorpej } 85695a65560Sthorpej 85795a65560Sthorpej static void 85895a65560Sthorpej tbr_install(const char *ifname) 85995a65560Sthorpej { 86095a65560Sthorpej struct tbrinfo *info; 86195a65560Sthorpej struct tbrreq req; 86295a65560Sthorpej int fd; 86395a65560Sthorpej 86495a65560Sthorpej LIST_FOREACH(info, &tbr_list, link) 86595a65560Sthorpej if (strcmp(info->ifname, ifname) == 0) 86695a65560Sthorpej break; 86795a65560Sthorpej if (info == NULL) 86895a65560Sthorpej return; 86995a65560Sthorpej if (info->tb_prof.rate == 0 || info->installed) 87095a65560Sthorpej return; 87195a65560Sthorpej 87295a65560Sthorpej /* get the current token bucket regulator */ 87395a65560Sthorpej if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 87495a65560Sthorpej err(1, "can't open altq device"); 87595a65560Sthorpej strncpy(req.ifname, ifname, IFNAMSIZ-1); 87695a65560Sthorpej if (ioctl(fd, ALTQTBRGET, &req) < 0) 87795a65560Sthorpej err(1, "ALTQTBRGET for interface %s", req.ifname); 87895a65560Sthorpej 87995a65560Sthorpej /* save the current values */ 88095a65560Sthorpej info->otb_prof.rate = req.tb_prof.rate; 88195a65560Sthorpej info->otb_prof.depth = req.tb_prof.depth; 88295a65560Sthorpej 88395a65560Sthorpej /* 88495a65560Sthorpej * if tbr is not specified in the config file and tbr is already 88595a65560Sthorpej * configured, do not change. 88695a65560Sthorpej */ 88795a65560Sthorpej if (req.tb_prof.rate != 0) { 88895a65560Sthorpej LOG(LOG_INFO, 0, 88995a65560Sthorpej "tbr is already installed on %s,\n" 890d5e1f166Sitojun " using the current setting (rate:%.2fM size:%.2fK).", 89195a65560Sthorpej info->ifname, 89295a65560Sthorpej (double)req.tb_prof.rate/1000000.0, 89395a65560Sthorpej (double)req.tb_prof.depth/1024.0); 89495a65560Sthorpej close (fd); 89595a65560Sthorpej return; 89695a65560Sthorpej } 89795a65560Sthorpej 89895a65560Sthorpej /* if the new size is not specified, use heuristics */ 89995a65560Sthorpej if (info->tb_prof.depth == 0) { 90095a65560Sthorpej u_int rate, size; 90195a65560Sthorpej 90295a65560Sthorpej rate = info->tb_prof.rate; 90395a65560Sthorpej if (rate <= 1*1000*1000) 90495a65560Sthorpej size = 1; 90595a65560Sthorpej else if (rate <= 10*1000*1000) 90695a65560Sthorpej size = 4; 90795a65560Sthorpej else if (rate <= 200*1000*1000) 90895a65560Sthorpej size = 8; 90995a65560Sthorpej else 91095a65560Sthorpej size = 24; 91195a65560Sthorpej size = size * 1500; /* assume the default mtu is 1500 */ 91295a65560Sthorpej info->tb_prof.depth = size; 91395a65560Sthorpej } 91495a65560Sthorpej 91595a65560Sthorpej /* install the new tbr */ 91695a65560Sthorpej strncpy(req.ifname, ifname, IFNAMSIZ-1); 91795a65560Sthorpej req.tb_prof.rate = info->tb_prof.rate; 91895a65560Sthorpej req.tb_prof.depth = info->tb_prof.depth; 91995a65560Sthorpej if (ioctl(fd, ALTQTBRSET, &req) < 0) 92095a65560Sthorpej err(1, "ALTQTBRSET for interface %s", req.ifname); 92195a65560Sthorpej LOG(LOG_INFO, 0, 922d5e1f166Sitojun "tbr installed on %s (rate:%.2fM size:%.2fK)", 92395a65560Sthorpej info->ifname, 92495a65560Sthorpej (double)info->tb_prof.rate/1000000.0, 92595a65560Sthorpej (double)info->tb_prof.depth/1024.0); 92695a65560Sthorpej close(fd); 92795a65560Sthorpej info->installed = 1; 92895a65560Sthorpej } 92995a65560Sthorpej 93095a65560Sthorpej static void 93195a65560Sthorpej tbr_deinstall(const char *ifname) 93295a65560Sthorpej { 93395a65560Sthorpej struct tbrinfo *info; 93495a65560Sthorpej struct tbrreq req; 93595a65560Sthorpej int fd; 93695a65560Sthorpej 93795a65560Sthorpej LIST_FOREACH(info, &tbr_list, link) 93895a65560Sthorpej if (strcmp(info->ifname, ifname) == 0) 93995a65560Sthorpej break; 94095a65560Sthorpej if (info == NULL) 94195a65560Sthorpej return; 94295a65560Sthorpej 94395a65560Sthorpej /* if we installed tbr, restore the old values */ 94495a65560Sthorpej if (info->installed != 0) { 94595a65560Sthorpej strncpy(req.ifname, ifname, IFNAMSIZ-1); 94695a65560Sthorpej req.tb_prof.rate = info->otb_prof.rate; 94795a65560Sthorpej req.tb_prof.depth = info->otb_prof.depth; 94895a65560Sthorpej if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 94995a65560Sthorpej err(1, "can't open altq device"); 95095a65560Sthorpej if (ioctl(fd, ALTQTBRSET, &req) < 0) 95195a65560Sthorpej err(1, "ALTQTBRSET for interface %s", req.ifname); 95295a65560Sthorpej close(fd); 95395a65560Sthorpej } 95495a65560Sthorpej LIST_REMOVE(info, link); 95595a65560Sthorpej free(info); 95695a65560Sthorpej } 95795a65560Sthorpej 95895a65560Sthorpej void 95995a65560Sthorpej print_filter(const struct flow_filter *filt) 96095a65560Sthorpej { 96195a65560Sthorpej if (filt->ff_flow.fi_family == AF_INET) { 96295a65560Sthorpej struct in_addr in_addr; 96395a65560Sthorpej 96495a65560Sthorpej in_addr.s_addr = filt->ff_flow.fi_dst.s_addr; 96595a65560Sthorpej LOG(LOG_DEBUG, 0, 966d5e1f166Sitojun " Filter Dest Addr: %s (mask %#x) Port: %d", 96795a65560Sthorpej inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_dst.s_addr), 96895a65560Sthorpej ntoh16(filt->ff_flow.fi_dport)); 96995a65560Sthorpej in_addr.s_addr = filt->ff_flow.fi_src.s_addr; 97095a65560Sthorpej LOG(LOG_DEBUG, 0, 971d5e1f166Sitojun " Src Addr: %s (mask %#x) Port: %d", 97295a65560Sthorpej inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_src.s_addr), 97395a65560Sthorpej ntoh16(filt->ff_flow.fi_sport)); 974d5e1f166Sitojun LOG(LOG_DEBUG, 0, " Protocol: %d TOS %#x (mask %#x)", 97595a65560Sthorpej filt->ff_flow.fi_proto, filt->ff_flow.fi_tos, 97695a65560Sthorpej filt->ff_mask.mask_tos); 97795a65560Sthorpej } 97895a65560Sthorpej #ifdef INET6 97995a65560Sthorpej else if (filt->ff_flow.fi_family == AF_INET6) { 98095a65560Sthorpej char str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN]; 98195a65560Sthorpej const struct flow_filter6 *sfilt6; 98295a65560Sthorpej 98395a65560Sthorpej sfilt6 = (const struct flow_filter6 *)filt; 98495a65560Sthorpej LOG(LOG_DEBUG, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d", 98595a65560Sthorpej inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_dst, 98695a65560Sthorpej str1, sizeof(str1)), 98795a65560Sthorpej inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_dst, 98895a65560Sthorpej str2, sizeof(str2)), 98995a65560Sthorpej ntoh16(sfilt6->ff_flow6.fi6_dport)); 99095a65560Sthorpej LOG(LOG_DEBUG, 0, " Src Addr: %s (mask %s) Port: %d", 99195a65560Sthorpej inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_src, 99295a65560Sthorpej str1, sizeof(str1)), 99395a65560Sthorpej inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_src, 99495a65560Sthorpej str2, sizeof(str2)), 99595a65560Sthorpej ntoh16(sfilt6->ff_flow6.fi6_sport)); 996d5e1f166Sitojun LOG(LOG_DEBUG, 0, " Protocol: %d TCLASS %#x (mask %#x)", 99795a65560Sthorpej sfilt6->ff_flow6.fi6_proto, sfilt6->ff_flow6.fi6_tclass, 99895a65560Sthorpej sfilt6->ff_mask6.mask6_tclass); 99995a65560Sthorpej } 100095a65560Sthorpej #endif /* INET6 */ 100195a65560Sthorpej } 100295a65560Sthorpej 100395a65560Sthorpej /* 100495a65560Sthorpej * functions to check the filter-rules. 100595a65560Sthorpej * when a new filter is added, we check the relation to the existing filters 100695a65560Sthorpej * and if some inconsistency is found, produce an error or a warning message. 100795a65560Sthorpej * 100895a65560Sthorpej * filter matching is performed from the head of the list. 100995a65560Sthorpej * let 101095a65560Sthorpej * S: a set of packets that filter s matches 101195a65560Sthorpej * T: a set of packets that filter t matches 101295a65560Sthorpej * filter relations are: 101395a65560Sthorpej * disjoint: S ^ T = empty 101495a65560Sthorpej * subset: S <= T 101595a65560Sthorpej * intersect: S ^ T = not empty 101695a65560Sthorpej * 101795a65560Sthorpej * a new filter is disjoint or subset of the existing filters --> ok 101895a65560Sthorpej * a new filter is superset of an existing filter --> order problem 101995a65560Sthorpej * a new filter intersect an existing filter --> warning 102095a65560Sthorpej * 102195a65560Sthorpej * port-intersect: a special case we don't make warning 102295a65560Sthorpej * - intersection is only port numbers 102395a65560Sthorpej * - one specifies src port and the other specifies dst port 102495a65560Sthorpej * there must be no packet with well-known port numbers in 102595a65560Sthorpej * both src and dst ports. so this is ok. 102695a65560Sthorpej */ 102795a65560Sthorpej 102895a65560Sthorpej #define FILT_DISJOINT 1 102995a65560Sthorpej #define FILT_SUBSET 2 103095a65560Sthorpej #define FILT_SUPERSET 3 103195a65560Sthorpej #define FILT_INTERSECT 4 103295a65560Sthorpej #define FILT_PORTINTERSECT 5 103395a65560Sthorpej 103495a65560Sthorpej static int 103595a65560Sthorpej add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo, 103695a65560Sthorpej struct fltrinfo **conflict) 103795a65560Sthorpej { 103895a65560Sthorpej struct fltrinfo *fp, *front, *back, *prev = NULL; 103995a65560Sthorpej int relation; 104095a65560Sthorpej 104195a65560Sthorpej LIST_FOREACH(fp, &ifinfo->fltr_rules, nextrule) { 104295a65560Sthorpej if (fp->fltr.ff_ruleno > fltrinfo->fltr.ff_ruleno) { 104395a65560Sthorpej front = fp; 104495a65560Sthorpej back = fltrinfo; 104595a65560Sthorpej prev = fp; 104695a65560Sthorpej } else { 104795a65560Sthorpej front = fltrinfo; 104895a65560Sthorpej back = fp; 104995a65560Sthorpej } 105095a65560Sthorpej 105195a65560Sthorpej relation = filt_check_relation(&front->fltr, &back->fltr); 105295a65560Sthorpej 105395a65560Sthorpej switch (relation) { 105495a65560Sthorpej case FILT_SUBSET: 105595a65560Sthorpej case FILT_DISJOINT: 105695a65560Sthorpej /* OK */ 105795a65560Sthorpej break; 105895a65560Sthorpej case FILT_SUPERSET: 105995a65560Sthorpej if (front->dontwarn == 0 && back->dontwarn == 0) 106095a65560Sthorpej LOG(LOG_ERR, 0, 1061d5e1f166Sitojun "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!", 106295a65560Sthorpej front->clinfo->clname, front->line_no, 106395a65560Sthorpej back->clinfo->clname, back->line_no); 106495a65560Sthorpej 106595a65560Sthorpej if (conflict != NULL) 106695a65560Sthorpej *conflict = fp; 106795a65560Sthorpej return (QOPERR_FILTER_SHADOW); 106895a65560Sthorpej case FILT_PORTINTERSECT: 106995a65560Sthorpej break; 107095a65560Sthorpej case FILT_INTERSECT: 107195a65560Sthorpej /* 10722fbcff73Sandvar * if the intersecting two filters belonging to the 107395a65560Sthorpej * same class, it's ok. 107495a65560Sthorpej */ 107595a65560Sthorpej if (front->clinfo == back->clinfo) 107695a65560Sthorpej break; 107795a65560Sthorpej if (front->dontwarn == 0 && back->dontwarn == 0) 107895a65560Sthorpej LOG(LOG_WARNING, 0, 1079d5e1f166Sitojun "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d", 108095a65560Sthorpej front->clinfo->clname, front->line_no, 108195a65560Sthorpej back->clinfo->clname, back->line_no); 108295a65560Sthorpej break; 108395a65560Sthorpej } 108495a65560Sthorpej } 108595a65560Sthorpej 108695a65560Sthorpej if (prev == NULL) 108795a65560Sthorpej LIST_INSERT_HEAD(&ifinfo->fltr_rules, fltrinfo, nextrule); 108895a65560Sthorpej else 108995a65560Sthorpej LIST_INSERT_AFTER(prev, fltrinfo, nextrule); 109095a65560Sthorpej return (0); 109195a65560Sthorpej } 109295a65560Sthorpej 109395a65560Sthorpej static int 109495a65560Sthorpej remove_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo) 109595a65560Sthorpej { 109695a65560Sthorpej LIST_REMOVE(fltrinfo, nextrule); 109795a65560Sthorpej return (0); 109895a65560Sthorpej } 109995a65560Sthorpej 110095a65560Sthorpej static int 110195a65560Sthorpej filt_check_relation(struct flow_filter *front, struct flow_filter *back) 110295a65560Sthorpej { 110395a65560Sthorpej int rval; 110495a65560Sthorpej 110595a65560Sthorpej if (front->ff_flow.fi_family != back->ff_flow.fi_family) 110695a65560Sthorpej return (FILT_DISJOINT); 110795a65560Sthorpej 110895a65560Sthorpej if (filt_disjoint(front, back)) 110995a65560Sthorpej return (FILT_DISJOINT); 111095a65560Sthorpej 111195a65560Sthorpej if ((rval = filt_subset(front, back)) == 1) 111295a65560Sthorpej return (FILT_SUBSET); 111395a65560Sthorpej 111495a65560Sthorpej if (filt_subset(back, front) == 1) 111595a65560Sthorpej return (FILT_SUPERSET); 111695a65560Sthorpej 111795a65560Sthorpej if (rval == 2) 111895a65560Sthorpej return (FILT_PORTINTERSECT); 111995a65560Sthorpej 112095a65560Sthorpej return (FILT_INTERSECT); 112195a65560Sthorpej } 112295a65560Sthorpej 112395a65560Sthorpej static int 112495a65560Sthorpej filt_disjoint(struct flow_filter *front, struct flow_filter *back) 112595a65560Sthorpej { 112695a65560Sthorpej u_int32_t mask; 112795a65560Sthorpej u_int8_t tosmask; 112895a65560Sthorpej 112995a65560Sthorpej if (front->ff_flow.fi_family == AF_INET) { 113095a65560Sthorpej if (front->ff_flow.fi_proto != 0 && back->ff_flow.fi_proto != 0 113195a65560Sthorpej && front->ff_flow.fi_proto != back->ff_flow.fi_proto) 113295a65560Sthorpej return (1); 113395a65560Sthorpej if (front->ff_flow.fi_sport != 0 && back->ff_flow.fi_sport != 0 113495a65560Sthorpej && front->ff_flow.fi_sport != back->ff_flow.fi_sport) 113595a65560Sthorpej return (1); 113695a65560Sthorpej if (front->ff_flow.fi_dport != 0 && back->ff_flow.fi_dport != 0 113795a65560Sthorpej && front->ff_flow.fi_dport != back->ff_flow.fi_dport) 113895a65560Sthorpej return (1); 113995a65560Sthorpej if (front->ff_flow.fi_gpi != 0 && back->ff_flow.fi_gpi != 0 114095a65560Sthorpej && front->ff_flow.fi_gpi != back->ff_flow.fi_gpi) 114195a65560Sthorpej return (1); 114295a65560Sthorpej if (front->ff_flow.fi_src.s_addr != 0 && 114395a65560Sthorpej back->ff_flow.fi_src.s_addr != 0) { 114495a65560Sthorpej mask = front->ff_mask.mask_src.s_addr & 114595a65560Sthorpej back->ff_mask.mask_src.s_addr; 114695a65560Sthorpej if ((front->ff_flow.fi_src.s_addr & mask) != 114795a65560Sthorpej (back->ff_flow.fi_src.s_addr & mask)) 114895a65560Sthorpej return (1); 114995a65560Sthorpej } 115095a65560Sthorpej if (front->ff_flow.fi_dst.s_addr != 0 && 115195a65560Sthorpej back->ff_flow.fi_dst.s_addr != 0) { 115295a65560Sthorpej mask = front->ff_mask.mask_dst.s_addr & 115395a65560Sthorpej back->ff_mask.mask_dst.s_addr; 115495a65560Sthorpej if ((front->ff_flow.fi_dst.s_addr & mask) != 115595a65560Sthorpej (back->ff_flow.fi_dst.s_addr & mask)) 115695a65560Sthorpej return (1); 115795a65560Sthorpej } 115895a65560Sthorpej if (front->ff_flow.fi_tos != 0 && back->ff_flow.fi_tos != 0) { 115995a65560Sthorpej tosmask = front->ff_mask.mask_tos & 116095a65560Sthorpej back->ff_mask.mask_tos; 116195a65560Sthorpej if ((front->ff_flow.fi_tos & tosmask) != 116295a65560Sthorpej (back->ff_flow.fi_tos & tosmask)) 116395a65560Sthorpej return (1); 116495a65560Sthorpej } 116595a65560Sthorpej return (0); 116695a65560Sthorpej } 116795a65560Sthorpej #ifdef INET6 116895a65560Sthorpej else if (front->ff_flow.fi_family == AF_INET6) { 116995a65560Sthorpej struct flow_filter6 *front6, *back6; 117095a65560Sthorpej int i; 117195a65560Sthorpej 117295a65560Sthorpej front6 = (struct flow_filter6 *)front; 117395a65560Sthorpej back6 = (struct flow_filter6 *)back; 117495a65560Sthorpej 117595a65560Sthorpej if (front6->ff_flow6.fi6_proto != 0 && 117695a65560Sthorpej back6->ff_flow6.fi6_proto != 0 && 117795a65560Sthorpej front6->ff_flow6.fi6_proto != back6->ff_flow6.fi6_proto) 117895a65560Sthorpej return (1); 117995a65560Sthorpej if (front6->ff_flow6.fi6_flowlabel != 0 && 118095a65560Sthorpej back6->ff_flow6.fi6_flowlabel != 0 && 118195a65560Sthorpej front6->ff_flow6.fi6_flowlabel != 118295a65560Sthorpej back6->ff_flow6.fi6_flowlabel) 118395a65560Sthorpej return (1); 118495a65560Sthorpej if (front6->ff_flow6.fi6_sport != 0 && 118595a65560Sthorpej back6->ff_flow6.fi6_sport != 0 && 118695a65560Sthorpej front6->ff_flow6.fi6_sport != back6->ff_flow6.fi6_sport) 118795a65560Sthorpej return (1); 118895a65560Sthorpej if (front6->ff_flow6.fi6_dport != 0 && 118995a65560Sthorpej back6->ff_flow6.fi6_dport != 0 && 119095a65560Sthorpej front6->ff_flow6.fi6_dport != back6->ff_flow6.fi6_dport) 119195a65560Sthorpej return (1); 119295a65560Sthorpej if (front6->ff_flow6.fi6_gpi != 0 && 119395a65560Sthorpej back6->ff_flow6.fi6_gpi != 0 && 119495a65560Sthorpej front6->ff_flow6.fi6_gpi != back6->ff_flow6.fi6_gpi) 119595a65560Sthorpej return (1); 119695a65560Sthorpej if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src) && 119795a65560Sthorpej !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) { 119895a65560Sthorpej for (i=0; i<4; i++) { 11990d33c75cSchristos mask = IN6ADDR32_GET(&front6->ff_mask6.mask6_src, i) 12000d33c75cSchristos & IN6ADDR32_GET(&back6->ff_mask6.mask6_src, i); 12010d33c75cSchristos if ((IN6ADDR32_GET(&front6->ff_flow6.fi6_src, i) & mask) != 12020d33c75cSchristos (IN6ADDR32_GET(&back6->ff_flow6.fi6_src, i) & mask)) 120395a65560Sthorpej return (1); 120495a65560Sthorpej } 120595a65560Sthorpej } 120695a65560Sthorpej if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst) && 120795a65560Sthorpej !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) { 120895a65560Sthorpej for (i=0; i<4; i++) { 12090d33c75cSchristos mask = IN6ADDR32_GET(&front6->ff_mask6.mask6_dst, i) 12100d33c75cSchristos & IN6ADDR32_GET(&back6->ff_mask6.mask6_dst, i); 12110d33c75cSchristos if ((IN6ADDR32_GET(&front6->ff_flow6.fi6_dst, i) & mask) != 12120d33c75cSchristos (IN6ADDR32_GET(&back6->ff_flow6.fi6_dst, i) & mask)) 121395a65560Sthorpej return (1); 121495a65560Sthorpej } 121595a65560Sthorpej } 121695a65560Sthorpej if (front6->ff_flow6.fi6_tclass != 0 && 121795a65560Sthorpej back6->ff_flow6.fi6_tclass != 0) { 121895a65560Sthorpej tosmask = front6->ff_mask6.mask6_tclass & 121995a65560Sthorpej back6->ff_mask6.mask6_tclass; 122095a65560Sthorpej if ((front6->ff_flow6.fi6_tclass & tosmask) != 122195a65560Sthorpej (back6->ff_flow6.fi6_tclass & tosmask)) 122295a65560Sthorpej return (1); 122395a65560Sthorpej } 122495a65560Sthorpej return (0); 122595a65560Sthorpej } 122695a65560Sthorpej #endif /* INET6 */ 122795a65560Sthorpej return (0); 122895a65560Sthorpej } 122995a65560Sthorpej 123095a65560Sthorpej /* 123195a65560Sthorpej * check if "front" is a subset of "back". assumes they are not disjoint 123295a65560Sthorpej * return value 0: not a subset 123395a65560Sthorpej * 1: subset 123495a65560Sthorpej * 2: subset except src & dst ports 123595a65560Sthorpej * (possible port-intersect) 123695a65560Sthorpej */ 123795a65560Sthorpej static int 123895a65560Sthorpej filt_subset(struct flow_filter *front, struct flow_filter *back) 123995a65560Sthorpej { 124095a65560Sthorpej u_int16_t srcport, dstport; 124195a65560Sthorpej 124295a65560Sthorpej if (front->ff_flow.fi_family == AF_INET) { 124395a65560Sthorpej if (front->ff_flow.fi_proto == 0 && 124495a65560Sthorpej back->ff_flow.fi_proto != 0) 124595a65560Sthorpej return (0); 124695a65560Sthorpej if (front->ff_flow.fi_gpi == 0 && back->ff_flow.fi_gpi != 0) 124795a65560Sthorpej return (0); 124895a65560Sthorpej if (front->ff_flow.fi_src.s_addr == 0) { 124995a65560Sthorpej if (back->ff_flow.fi_src.s_addr != 0) 125095a65560Sthorpej return (0); 125195a65560Sthorpej } else if (back->ff_flow.fi_src.s_addr != 0 && 125295a65560Sthorpej (~front->ff_mask.mask_src.s_addr & 125395a65560Sthorpej back->ff_mask.mask_src.s_addr)) 125495a65560Sthorpej return (0); 125595a65560Sthorpej if (front->ff_flow.fi_dst.s_addr == 0) { 125695a65560Sthorpej if (back->ff_flow.fi_dst.s_addr != 0) 125795a65560Sthorpej return (0); 125895a65560Sthorpej } else if (back->ff_flow.fi_dst.s_addr != 0 && 125995a65560Sthorpej (~front->ff_mask.mask_dst.s_addr & 126095a65560Sthorpej back->ff_mask.mask_dst.s_addr)) 126195a65560Sthorpej return (0); 126295a65560Sthorpej if (~front->ff_mask.mask_tos & back->ff_mask.mask_tos) 126395a65560Sthorpej return (0); 126495a65560Sthorpej 126595a65560Sthorpej if (front->ff_flow.fi_sport == 0 && 126695a65560Sthorpej back->ff_flow.fi_sport != 0) { 126795a65560Sthorpej srcport = ntohs(back->ff_flow.fi_sport); 126895a65560Sthorpej dstport = ntohs(front->ff_flow.fi_dport); 126995a65560Sthorpej if (dstport > 0 /* && dstport < 1024 */ && 127095a65560Sthorpej srcport > 0 /* && srcport < 1024 */) 127195a65560Sthorpej return (2); 127295a65560Sthorpej return (0); 127395a65560Sthorpej } 127495a65560Sthorpej if (front->ff_flow.fi_dport == 0 && 127595a65560Sthorpej back->ff_flow.fi_dport != 0) { 127695a65560Sthorpej dstport = ntohs(back->ff_flow.fi_dport); 127795a65560Sthorpej srcport = ntohs(front->ff_flow.fi_sport); 127895a65560Sthorpej if (srcport > 0 /* && srcport < 1024 */ && 127995a65560Sthorpej dstport > 0 /* && dstport < 1024 */) 128095a65560Sthorpej return (2); 128195a65560Sthorpej return (0); 128295a65560Sthorpej } 128395a65560Sthorpej 128495a65560Sthorpej return (1); 128595a65560Sthorpej } 128695a65560Sthorpej #ifdef INET6 128795a65560Sthorpej else if (front->ff_flow.fi_family == AF_INET6) { 128895a65560Sthorpej struct flow_filter6 *front6, *back6; 128995a65560Sthorpej int i; 129095a65560Sthorpej 129195a65560Sthorpej front6 = (struct flow_filter6 *)front; 129295a65560Sthorpej back6 = (struct flow_filter6 *)back; 129395a65560Sthorpej 129495a65560Sthorpej if (front6->ff_flow6.fi6_proto == 0 && 129595a65560Sthorpej back6->ff_flow6.fi6_proto != 0) 129695a65560Sthorpej return (0); 129795a65560Sthorpej if (front6->ff_flow6.fi6_flowlabel == 0 && 129895a65560Sthorpej back6->ff_flow6.fi6_flowlabel != 0) 129995a65560Sthorpej return (0); 130095a65560Sthorpej if (front6->ff_flow6.fi6_gpi == 0 && 130195a65560Sthorpej back6->ff_flow6.fi6_gpi != 0) 130295a65560Sthorpej return (0); 130395a65560Sthorpej 130495a65560Sthorpej if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src)) { 130595a65560Sthorpej if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 130695a65560Sthorpej return (0); 130795a65560Sthorpej } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 130895a65560Sthorpej for (i=0; i<4; i++) 13090d33c75cSchristos if (~IN6ADDR32_GET(&front6->ff_mask6.mask6_src, i) & 13100d33c75cSchristos IN6ADDR32_GET(&back6->ff_mask6.mask6_src, i)) 131195a65560Sthorpej return (0); 131295a65560Sthorpej if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst)) { 131395a65560Sthorpej if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 131495a65560Sthorpej return (0); 131595a65560Sthorpej } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 131695a65560Sthorpej for (i=0; i<4; i++) 13170d33c75cSchristos if (~IN6ADDR32_GET(&front6->ff_mask6.mask6_dst, i) & 13180d33c75cSchristos IN6ADDR32_GET(&back6->ff_mask6.mask6_dst, i)) 131995a65560Sthorpej return (0); 132095a65560Sthorpej 132195a65560Sthorpej if (~front6->ff_mask6.mask6_tclass & 132295a65560Sthorpej back6->ff_mask6.mask6_tclass) 132395a65560Sthorpej return (0); 132495a65560Sthorpej 132595a65560Sthorpej if (front6->ff_flow6.fi6_sport == 0 && 132695a65560Sthorpej back6->ff_flow6.fi6_sport != 0) { 132795a65560Sthorpej srcport = ntohs(back6->ff_flow6.fi6_sport); 132895a65560Sthorpej dstport = ntohs(front6->ff_flow6.fi6_dport); 132995a65560Sthorpej if (dstport > 0 /* && dstport < 1024 */ && 133095a65560Sthorpej srcport > 0 /* && srcport < 1024 */) 133195a65560Sthorpej return (2); 133295a65560Sthorpej return (0); 133395a65560Sthorpej } 133495a65560Sthorpej if (front6->ff_flow6.fi6_dport == 0 && 133595a65560Sthorpej back6->ff_flow6.fi6_dport != 0) { 133695a65560Sthorpej dstport = ntohs(back6->ff_flow6.fi6_dport); 133795a65560Sthorpej srcport = ntohs(front6->ff_flow6.fi6_sport); 133895a65560Sthorpej if (srcport > 0 /* && srcport < 1024 */ && 133995a65560Sthorpej dstport > 0 /* && dstport < 1024 */) 134095a65560Sthorpej return (2); 134195a65560Sthorpej return (0); 134295a65560Sthorpej } 134395a65560Sthorpej } 134495a65560Sthorpej #endif /* INET6 */ 134595a65560Sthorpej return (1); 134695a65560Sthorpej } 134795a65560Sthorpej 134895a65560Sthorpej 134995a65560Sthorpej /* 135095a65560Sthorpej * setting RED or RIO default parameters 135195a65560Sthorpej */ 135295a65560Sthorpej int 135395a65560Sthorpej qop_red_set_defaults(int th_min, int th_max, int inv_pmax) 135495a65560Sthorpej { 135595a65560Sthorpej struct redparams params; 135695a65560Sthorpej int fd; 135795a65560Sthorpej 135895a65560Sthorpej if ((fd = open(RED_DEVICE, O_RDWR)) < 0) { 1359d5e1f166Sitojun LOG(LOG_ERR, errno, "RED open"); 136095a65560Sthorpej return (QOPERR_SYSCALL); 136195a65560Sthorpej } 136295a65560Sthorpej 136395a65560Sthorpej params.th_min = th_min; 136495a65560Sthorpej params.th_max = th_max; 136595a65560Sthorpej params.inv_pmax = inv_pmax; 136695a65560Sthorpej 136795a65560Sthorpej if (ioctl(fd, RED_SETDEFAULTS, ¶ms) < 0) { 1368d5e1f166Sitojun LOG(LOG_ERR, errno, "RED_SETDEFAULTS"); 1369baacf5e0Swiz (void)close(fd); 137095a65560Sthorpej return (QOPERR_SYSCALL); 137195a65560Sthorpej } 137295a65560Sthorpej 137395a65560Sthorpej (void)close(fd); 137495a65560Sthorpej return (0); 137595a65560Sthorpej } 137695a65560Sthorpej 137795a65560Sthorpej int 137895a65560Sthorpej qop_rio_set_defaults(struct redparams *params) 137995a65560Sthorpej { 138095a65560Sthorpej int i, fd; 138195a65560Sthorpej 138295a65560Sthorpej /* sanity check */ 138395a65560Sthorpej for (i = 1; i < RIO_NDROPPREC; i++) { 138495a65560Sthorpej if (params[i].th_max > params[i-1].th_min) 138595a65560Sthorpej LOG(LOG_WARNING, 0, 1386d5e1f166Sitojun "warning: overlap found in RIO thresholds"); 138795a65560Sthorpej } 138895a65560Sthorpej 138995a65560Sthorpej if ((fd = open(RIO_DEVICE, O_RDWR)) < 0) { 1390d5e1f166Sitojun LOG(LOG_ERR, errno, "RIO open"); 139195a65560Sthorpej return (QOPERR_SYSCALL); 139295a65560Sthorpej } 139395a65560Sthorpej 139495a65560Sthorpej if (ioctl(fd, RIO_SETDEFAULTS, params) < 0) { 1395d5e1f166Sitojun LOG(LOG_ERR, errno, "RIO_SETDEFAULTS"); 1396baacf5e0Swiz (void)close(fd); 139795a65560Sthorpej return (QOPERR_SYSCALL); 139895a65560Sthorpej } 139995a65560Sthorpej 140095a65560Sthorpej (void)close(fd); 140195a65560Sthorpej return (0); 140295a65560Sthorpej } 140395a65560Sthorpej 140495a65560Sthorpej /* 140595a65560Sthorpej * try to load and open KLD module 1406d5e1f166Sitojun * (also check the altq device file) 140795a65560Sthorpej */ 140895a65560Sthorpej int 14097097d2c1Sxtraeme open_module(const char *dvname, int flags) 141095a65560Sthorpej { 141195a65560Sthorpej #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 14128b8734d2Sitojun char modname[64], filename[MAXPATHLEN], *cp; 141395a65560Sthorpej int fd; 1414d5e1f166Sitojun #endif 141595a65560Sthorpej struct stat sbuf; 141695a65560Sthorpej 1417d5e1f166Sitojun /* check if the altq device exists */ 14187097d2c1Sxtraeme if (stat(dvname, &sbuf) < 0) { 14197097d2c1Sxtraeme LOG(LOG_ERR, errno, "can't access %s!", dvname); 1420d5e1f166Sitojun return (-1); 1421d5e1f166Sitojun } 1422d5e1f166Sitojun 1423d5e1f166Sitojun #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 142495a65560Sthorpej /* turn discipline name into module name */ 14258b8734d2Sitojun strlcpy(modname, "altq_", sizeof(modname)); 142695a65560Sthorpej if ((cp = strrchr(devname, '/')) == NULL) 142795a65560Sthorpej return (-1); 14288b8734d2Sitojun strlcat(modname, cp + 1, sizeof(modname)); 142995a65560Sthorpej 143095a65560Sthorpej /* check if the kld module exists */ 14318b8734d2Sitojun snprintf(filename, sizeof(filename), "/modules/%s.ko", modname); 143295a65560Sthorpej if (stat(filename, &sbuf) < 0) { 143395a65560Sthorpej /* module file doesn't exist */ 143495a65560Sthorpej return (-1); 143595a65560Sthorpej } 143695a65560Sthorpej 143795a65560Sthorpej if (kldload(modname) < 0) { 1438d5e1f166Sitojun LOG(LOG_ERR, errno, "kldload %s failed!", modname); 143995a65560Sthorpej return (-1); 144095a65560Sthorpej } 144195a65560Sthorpej 144295a65560Sthorpej /* successfully loaded, open the device */ 1443d5e1f166Sitojun LOG(LOG_INFO, 0, "kld module %s loaded", modname); 144495a65560Sthorpej fd = open(devname, flags); 144595a65560Sthorpej return (fd); 144695a65560Sthorpej #else 144795a65560Sthorpej return (-1); 144895a65560Sthorpej #endif 144995a65560Sthorpej } 1450