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