Home | History | Annotate | Line # | Download | only in libaltq
qop_hfsc.c revision 1.7.12.1
      1  1.7.12.1    peter /*	$NetBSD: qop_hfsc.c,v 1.7.12.1 2006/03/18 12:12:59 peter Exp $	*/
      2  1.7.12.1    peter /*	$KAME: qop_hfsc.c,v 1.12 2005/01/05 04:53:47 itojun Exp $	*/
      3       1.1  thorpej /*
      4       1.1  thorpej  * Copyright (C) 1999-2000
      5       1.1  thorpej  *	Sony Computer Science Laboratories, Inc.  All rights reserved.
      6       1.1  thorpej  *
      7       1.1  thorpej  * Redistribution and use in source and binary forms, with or without
      8       1.1  thorpej  * modification, are permitted provided that the following conditions
      9       1.1  thorpej  * are met:
     10       1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     11       1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     12       1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     14       1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     15       1.1  thorpej  *
     16       1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
     17       1.1  thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18       1.1  thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19       1.1  thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
     20       1.1  thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21       1.1  thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22       1.1  thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23       1.1  thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24       1.1  thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25       1.1  thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26       1.1  thorpej  * SUCH DAMAGE.
     27       1.1  thorpej  */
     28       1.1  thorpej 
     29       1.1  thorpej #include <sys/param.h>
     30       1.1  thorpej #include <sys/socket.h>
     31       1.1  thorpej #include <sys/sockio.h>
     32       1.1  thorpej #include <sys/ioctl.h>
     33       1.1  thorpej #include <sys/fcntl.h>
     34       1.1  thorpej #include <net/if.h>
     35       1.1  thorpej #include <netinet/in.h>
     36       1.1  thorpej #include <arpa/inet.h>
     37       1.1  thorpej 
     38       1.1  thorpej #include <stdio.h>
     39       1.1  thorpej #include <stdlib.h>
     40       1.1  thorpej #include <unistd.h>
     41       1.1  thorpej #include <stddef.h>
     42       1.1  thorpej #include <string.h>
     43       1.1  thorpej #include <ctype.h>
     44       1.1  thorpej #include <errno.h>
     45       1.1  thorpej #include <syslog.h>
     46       1.1  thorpej #include <netdb.h>
     47       1.6   itojun #include <math.h>
     48       1.1  thorpej 
     49       1.1  thorpej #include <altq/altq.h>
     50       1.1  thorpej #include <altq/altq_hfsc.h>
     51       1.1  thorpej #include "altq_qop.h"
     52       1.1  thorpej #include "qop_hfsc.h"
     53       1.1  thorpej 
     54       1.2   itojun static int read_sc(int *, char ***, int *, u_int *, u_int *, u_int *);
     55       1.2   itojun static int qop_hfsc_enable_hook(struct ifinfo *);
     56       1.2   itojun static int qop_hfsc_delete_class_hook(struct classinfo *);
     57       1.2   itojun static int validate_sc(struct service_curve *);
     58       1.1  thorpej 
     59       1.2   itojun static void gsc_add_sc(struct gen_sc *, struct service_curve *);
     60       1.2   itojun static void gsc_sub_sc(struct gen_sc *, struct service_curve *);
     61       1.2   itojun static int is_gsc_under_sc(struct gen_sc *, struct service_curve *);
     62       1.2   itojun static void gsc_destroy(struct gen_sc *);
     63       1.2   itojun static struct segment *gsc_getentry(struct gen_sc *, double);
     64       1.2   itojun static int gsc_add_seg(struct gen_sc *, double, double, double, double);
     65       1.2   itojun static int gsc_sub_seg(struct gen_sc *, double, double, double, double);
     66       1.2   itojun static void gsc_compress(struct gen_sc *);
     67       1.2   itojun static double sc_x2y(struct service_curve *, double);
     68       1.1  thorpej 
     69       1.2   itojun static int hfsc_attach(struct ifinfo *);
     70       1.2   itojun static int hfsc_detach(struct ifinfo *);
     71       1.2   itojun static int hfsc_clear(struct ifinfo *);
     72       1.2   itojun static int hfsc_enable(struct ifinfo *);
     73       1.2   itojun static int hfsc_disable(struct ifinfo *);
     74       1.2   itojun static int hfsc_add_class(struct classinfo *);
     75       1.2   itojun static int hfsc_modify_class(struct classinfo *, void *);
     76       1.2   itojun static int hfsc_delete_class(struct classinfo *);
     77       1.2   itojun static int hfsc_add_filter(struct fltrinfo *);
     78       1.2   itojun static int hfsc_delete_filter(struct fltrinfo *);
     79       1.1  thorpej 
     80       1.1  thorpej #define HFSC_DEVICE	"/dev/altq/hfsc"
     81       1.1  thorpej 
     82       1.1  thorpej static int hfsc_fd = -1;
     83       1.1  thorpej static int hfsc_refcount = 0;
     84       1.1  thorpej 
     85       1.1  thorpej static struct qdisc_ops hfsc_qdisc = {
     86       1.1  thorpej 	ALTQT_HFSC,
     87       1.1  thorpej 	"hfsc",
     88       1.1  thorpej 	hfsc_attach,
     89       1.1  thorpej 	hfsc_detach,
     90       1.1  thorpej 	hfsc_clear,
     91       1.1  thorpej 	hfsc_enable,
     92       1.1  thorpej 	hfsc_disable,
     93       1.1  thorpej 	hfsc_add_class,
     94       1.1  thorpej 	hfsc_modify_class,
     95       1.1  thorpej 	hfsc_delete_class,
     96       1.1  thorpej 	hfsc_add_filter,
     97       1.1  thorpej 	hfsc_delete_filter,
     98       1.1  thorpej };
     99       1.1  thorpej 
    100       1.1  thorpej #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
    101       1.1  thorpej 
    102       1.1  thorpej /*
    103       1.1  thorpej  * parser interface
    104       1.1  thorpej  */
    105       1.1  thorpej int
    106       1.1  thorpej hfsc_interface_parser(const char *ifname, int argc, char **argv)
    107       1.1  thorpej {
    108       1.1  thorpej 	u_int  	bandwidth = 100000000;	/* 100Mbps */
    109       1.1  thorpej 	u_int	tbrsize = 0;
    110       1.1  thorpej 	int	flags = 0;
    111       1.1  thorpej 
    112       1.1  thorpej 	/*
    113       1.1  thorpej 	 * process options
    114       1.1  thorpej 	 */
    115       1.1  thorpej 	while (argc > 0) {
    116       1.1  thorpej 		if (EQUAL(*argv, "bandwidth")) {
    117       1.1  thorpej 			argc--; argv++;
    118       1.1  thorpej 			if (argc > 0)
    119       1.1  thorpej 				bandwidth = atobps(*argv);
    120       1.1  thorpej 		} else if (EQUAL(*argv, "tbrsize")) {
    121       1.1  thorpej 			argc--; argv++;
    122       1.1  thorpej 			if (argc > 0)
    123       1.1  thorpej 				tbrsize = atobytes(*argv);
    124       1.1  thorpej 		} else if (EQUAL(*argv, "hfsc")) {
    125       1.1  thorpej 			/* just skip */
    126       1.1  thorpej 		} else {
    127       1.5   itojun 			LOG(LOG_ERR, 0, "Unknown keyword '%s'", *argv);
    128       1.1  thorpej 			return (0);
    129       1.1  thorpej 		}
    130       1.1  thorpej 		argc--; argv++;
    131       1.1  thorpej 	}
    132       1.1  thorpej 
    133       1.1  thorpej 	if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
    134       1.1  thorpej 		return (0);
    135       1.1  thorpej 
    136       1.1  thorpej 	if (qcmd_hfsc_add_if(ifname, bandwidth, flags) != 0)
    137       1.1  thorpej 		return (0);
    138       1.1  thorpej 	return (1);
    139       1.1  thorpej }
    140       1.1  thorpej 
    141       1.1  thorpej int
    142       1.1  thorpej hfsc_class_parser(const char *ifname, const char *class_name,
    143       1.1  thorpej 		  const char *parent_name, int argc, char **argv)
    144       1.1  thorpej {
    145  1.7.12.1    peter 	u_int	m1, d, m2, rm1, rd, rm2, fm1, fd, fm2, um1, ud, um2;
    146       1.1  thorpej 	int	qlimit = 50;
    147       1.1  thorpej 	int	flags = 0, admission = 0;
    148       1.1  thorpej 	int	type = 0, error;
    149       1.1  thorpej 
    150  1.7.12.1    peter 	rm1 = rd = rm2 = fm1 = fd = fm2 = um1 = ud = um2 = 0;
    151       1.1  thorpej 	while (argc > 0) {
    152       1.1  thorpej 		if (*argv[0] == '[') {
    153       1.1  thorpej 			if (read_sc(&argc, &argv, &type, &m1, &d, &m2) != 0) {
    154       1.1  thorpej 				LOG(LOG_ERR, 0,
    155       1.4   itojun 				    "Bad service curve in %s, line %d",
    156       1.1  thorpej 				    altqconfigfile, line_no);
    157       1.1  thorpej 				return (0);
    158       1.1  thorpej 			}
    159       1.1  thorpej 			if (type & HFSC_REALTIMESC) {
    160       1.1  thorpej 				rm1 = m1; rd = d; rm2 = m2;
    161       1.1  thorpej 			}
    162       1.1  thorpej 			if (type & HFSC_LINKSHARINGSC) {
    163       1.1  thorpej 				fm1 = m1; fd = d; fm2 = m2;
    164       1.1  thorpej 			}
    165  1.7.12.1    peter 			if (type & HFSC_UPPERLIMITSC) {
    166  1.7.12.1    peter 				um1 = m1; ud = d; um2 = m2;
    167  1.7.12.1    peter 			}
    168  1.7.12.1    peter 		} else if (EQUAL(*argv, "ulimit")) {
    169  1.7.12.1    peter 			argc--; argv++;
    170  1.7.12.1    peter 			if (argc > 0) {
    171  1.7.12.1    peter 				um2 = atobps(*argv);
    172  1.7.12.1    peter 				type |= HFSC_UPPERLIMITSC;
    173  1.7.12.1    peter 			}
    174       1.1  thorpej 		} else if (EQUAL(*argv, "pshare")) {
    175       1.1  thorpej 			argc--; argv++;
    176       1.1  thorpej 			if (argc > 0) {
    177       1.1  thorpej 				struct ifinfo	*ifinfo;
    178       1.1  thorpej 				u_int pshare;
    179       1.1  thorpej 
    180       1.1  thorpej 				pshare = (u_int)strtoul(*argv, NULL, 0);
    181       1.1  thorpej 				if ((ifinfo = ifname2ifinfo(ifname)) != NULL) {
    182       1.1  thorpej 					fm2 = ifinfo->bandwidth / 100 * pshare;
    183       1.1  thorpej 					type |= HFSC_LINKSHARINGSC;
    184       1.1  thorpej 				}
    185       1.1  thorpej 			}
    186       1.1  thorpej 		} else if (EQUAL(*argv, "grate")) {
    187       1.1  thorpej 			argc--; argv++;
    188       1.1  thorpej 			if (argc > 0) {
    189       1.1  thorpej 				rm2 = atobps(*argv);
    190       1.1  thorpej 				type |= HFSC_REALTIMESC;
    191       1.1  thorpej 			}
    192  1.7.12.1    peter 		} else if (EQUAL(*argv, "bandwidth")) {
    193  1.7.12.1    peter 			argc--; argv++;
    194  1.7.12.1    peter 			if (argc > 0) {
    195  1.7.12.1    peter 				rm2 = fm2 = atobps(*argv);
    196  1.7.12.1    peter 				type |= (HFSC_REALTIMESC | HFSC_LINKSHARINGSC);
    197  1.7.12.1    peter 			}
    198       1.1  thorpej 		} else if (EQUAL(*argv, "qlimit")) {
    199       1.1  thorpej 			argc--; argv++;
    200       1.1  thorpej 			if (argc > 0)
    201       1.1  thorpej 				qlimit = strtoul(*argv, NULL, 0);
    202       1.1  thorpej 		} else if (EQUAL(*argv, "default")) {
    203       1.1  thorpej 			flags |= HFCF_DEFAULTCLASS;
    204       1.1  thorpej 		} else if (EQUAL(*argv, "admission")) {
    205       1.1  thorpej 			argc--; argv++;
    206       1.1  thorpej 			if (argc > 0) {
    207       1.1  thorpej 				if (EQUAL(*argv, "guaranteed")
    208       1.1  thorpej 				    || EQUAL(*argv, "cntlload"))
    209       1.1  thorpej 					admission = 1;
    210       1.1  thorpej 				else if (EQUAL(*argv, "none")) {
    211       1.1  thorpej 					/* nothing */
    212       1.1  thorpej 				} else {
    213       1.1  thorpej 					LOG(LOG_ERR, 0,
    214       1.4   itojun 					    "unknown admission type - %s, line %d",
    215       1.1  thorpej 					    *argv, line_no);
    216       1.1  thorpej 					return (0);
    217       1.1  thorpej 				}
    218       1.1  thorpej 			}
    219       1.1  thorpej 		} else if (EQUAL(*argv, "red")) {
    220       1.1  thorpej 			flags |= HFCF_RED;
    221       1.1  thorpej 		} else if (EQUAL(*argv, "ecn")) {
    222       1.1  thorpej 			flags |= HFCF_ECN;
    223       1.1  thorpej 		} else if (EQUAL(*argv, "rio")) {
    224       1.1  thorpej 			flags |= HFCF_RIO;
    225       1.1  thorpej 		} else if (EQUAL(*argv, "cleardscp")) {
    226       1.1  thorpej 			flags |= HFCF_CLEARDSCP;
    227       1.1  thorpej 		} else {
    228       1.1  thorpej 			LOG(LOG_ERR, 0,
    229       1.4   itojun 			    "Unknown keyword '%s' in %s, line %d",
    230       1.1  thorpej 			    *argv, altqconfigfile, line_no);
    231       1.1  thorpej 			return (0);
    232       1.1  thorpej 		}
    233       1.1  thorpej 
    234       1.1  thorpej 		argc--; argv++;
    235       1.1  thorpej 	}
    236       1.1  thorpej 
    237       1.1  thorpej 	if (type == 0) {
    238       1.1  thorpej 		LOG(LOG_ERR, 0,
    239       1.4   itojun 		    "hfsc: service curve not specified in %s, line %d",
    240       1.1  thorpej 		    altqconfigfile, line_no);
    241       1.1  thorpej 		return (0);
    242       1.1  thorpej 	}
    243       1.1  thorpej 
    244       1.1  thorpej 	if ((flags & HFCF_ECN) && (flags & (HFCF_RED|HFCF_RIO)) == 0)
    245       1.1  thorpej 		flags |= HFCF_RED;
    246       1.1  thorpej 
    247       1.1  thorpej 	/*
    248       1.1  thorpej 	 * if the link-sharing service curve is diffrent from
    249       1.1  thorpej 	 * the real-time service curve, we first create a class with the
    250       1.1  thorpej 	 * smaller service curve and then modify the other service curve.
    251       1.1  thorpej 	 */
    252       1.1  thorpej 	if (rm2 <= fm2) {
    253       1.1  thorpej 		m1 = rm1; d = rd; m2 = rm2;
    254       1.1  thorpej 	} else {
    255       1.1  thorpej 		m1 = fm1; d = fd; m2 = fm2;
    256       1.1  thorpej 	}
    257       1.1  thorpej 	error = qcmd_hfsc_add_class(ifname, class_name, parent_name,
    258       1.1  thorpej 				    m1, d, m2, qlimit, flags);
    259       1.1  thorpej 
    260       1.1  thorpej 	if (error == 0 && (rm1 != fm1 || rd != fd || rm2 != fm2)) {
    261       1.1  thorpej 		if (rm2 <= fm2) {
    262       1.1  thorpej 			m1 = fm1; d = fd; m2 = fm2; type = HFSC_LINKSHARINGSC;
    263       1.1  thorpej 		} else {
    264       1.1  thorpej 			m1 = rm1; d = rd; m2 = rm2; type = HFSC_REALTIMESC;
    265       1.1  thorpej 		}
    266       1.1  thorpej 		error = qcmd_hfsc_modify_class(ifname, class_name,
    267       1.1  thorpej 					       m1, d, m2, type);
    268       1.1  thorpej 	}
    269       1.1  thorpej 
    270  1.7.12.1    peter 	if (error == 0 && (um1 != 0 || um2 != 0)) {
    271  1.7.12.1    peter 		error = qcmd_hfsc_modify_class(ifname, class_name,
    272  1.7.12.1    peter 		    um1, ud, um2, HFSC_UPPERLIMITSC);
    273  1.7.12.1    peter 	}
    274  1.7.12.1    peter 
    275       1.1  thorpej 	if (error == 0 && admission) {
    276       1.1  thorpej 		/* this is a special class for rsvp */
    277       1.1  thorpej 		struct ifinfo *ifinfo = ifname2ifinfo(ifname);
    278       1.1  thorpej 		struct classinfo *clinfo = clname2clinfo(ifinfo, class_name);
    279       1.1  thorpej 
    280       1.1  thorpej 		if (ifinfo->resv_class != NULL) {
    281       1.1  thorpej 			LOG(LOG_ERR, 0,
    282       1.4   itojun 			    "more than one admission class specified: %s",
    283       1.1  thorpej 			    class_name);
    284       1.1  thorpej 			return (0);
    285       1.1  thorpej 		}
    286       1.1  thorpej 		ifinfo->resv_class = clinfo;
    287       1.1  thorpej 	}
    288       1.1  thorpej 
    289       1.1  thorpej 	if (error) {
    290       1.4   itojun 		LOG(LOG_ERR, errno, "hfsc_class_parser: %s",
    291       1.1  thorpej 		    qoperror(error));
    292       1.1  thorpej 		return (0);
    293       1.1  thorpej 	}
    294       1.1  thorpej 	return (1);
    295       1.1  thorpej }
    296       1.1  thorpej 
    297       1.1  thorpej /*
    298       1.1  thorpej  * read service curve parameters
    299       1.1  thorpej  * '[' <type> <m1> <d> <m2> ']'
    300  1.7.12.1    peter  *  type := "sc", "rt", "ls", or "ul"
    301       1.1  thorpej  */
    302       1.1  thorpej static int
    303       1.1  thorpej read_sc(int *argcp, char ***argvp, int *type, u_int *m1, u_int *d, u_int *m2)
    304       1.1  thorpej {
    305       1.1  thorpej 	int argc = *argcp;
    306       1.1  thorpej 	char **argv = *argvp;
    307       1.1  thorpej 	char *cp;
    308       1.1  thorpej 
    309       1.1  thorpej 	cp = *argv;
    310       1.1  thorpej 	if (*cp++ != '[')
    311       1.1  thorpej 		return (-1);
    312       1.1  thorpej 	if (*cp == '\0') {
    313       1.1  thorpej 		cp = *++argv; --argc;
    314       1.1  thorpej 	}
    315       1.1  thorpej 	if (*cp == 's' || *cp == 'S')
    316       1.1  thorpej 		*type = HFSC_DEFAULTSC;
    317       1.1  thorpej 	else if (*cp == 'r' || *cp == 'R')
    318       1.1  thorpej 		*type = HFSC_REALTIMESC;
    319       1.1  thorpej 	else if (*cp == 'l' || *cp == 'L')
    320       1.1  thorpej 		*type = HFSC_LINKSHARINGSC;
    321  1.7.12.1    peter 	else if (*cp == 'u' || *cp == 'U')
    322  1.7.12.1    peter 		*type = HFSC_UPPERLIMITSC;
    323       1.1  thorpej 	else
    324       1.1  thorpej 		return (-1);
    325       1.1  thorpej 	cp = *++argv; --argc;
    326       1.1  thorpej 	*m1 = atobps(cp);
    327       1.1  thorpej 	cp = *++argv; --argc;
    328       1.1  thorpej 	*d = (u_int)strtoul(cp, NULL, 0);
    329       1.1  thorpej 	cp = *++argv; --argc;
    330       1.1  thorpej 	*m2 = atobps(cp);
    331       1.1  thorpej 	if (strchr(cp, ']') == NULL) {
    332       1.1  thorpej 		cp = *++argv; --argc;
    333       1.1  thorpej 		if (*cp != ']')
    334       1.1  thorpej 			return (-1);
    335       1.1  thorpej 	}
    336       1.1  thorpej 	*argcp = argc;
    337       1.1  thorpej 	*argvp = argv;
    338       1.1  thorpej 	return (0);
    339       1.1  thorpej }
    340       1.1  thorpej 
    341       1.1  thorpej /*
    342       1.1  thorpej  * qcmd api
    343       1.1  thorpej  */
    344       1.1  thorpej int
    345       1.1  thorpej qcmd_hfsc_add_if(const char *ifname, u_int bandwidth, int flags)
    346       1.1  thorpej {
    347       1.1  thorpej 	int error;
    348  1.7.12.1    peter 
    349       1.1  thorpej 	error = qop_hfsc_add_if(NULL, ifname, bandwidth, flags);
    350       1.1  thorpej 	if (error != 0)
    351       1.4   itojun 		LOG(LOG_ERR, errno, "%s: can't add hfsc on interface '%s'",
    352       1.1  thorpej 		    qoperror(error), ifname);
    353       1.1  thorpej 	return (error);
    354       1.1  thorpej }
    355       1.1  thorpej 
    356       1.1  thorpej int
    357       1.1  thorpej qcmd_hfsc_add_class(const char *ifname, const char *class_name,
    358       1.1  thorpej 		    const char *parent_name, u_int m1, u_int d, u_int m2,
    359       1.1  thorpej 		    int qlimit, int flags)
    360       1.1  thorpej {
    361       1.1  thorpej 	struct ifinfo *ifinfo;
    362       1.1  thorpej 	struct classinfo *parent = NULL;
    363       1.1  thorpej 	struct service_curve sc;
    364       1.1  thorpej 	int error = 0;
    365       1.1  thorpej 
    366       1.1  thorpej 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
    367       1.1  thorpej 		error = QOPERR_BADIF;
    368       1.1  thorpej 
    369       1.1  thorpej 	if (error == 0 &&
    370       1.1  thorpej 	    (parent = clname2clinfo(ifinfo, parent_name)) == NULL)
    371       1.1  thorpej 		error = QOPERR_BADCLASS;
    372       1.1  thorpej 
    373       1.1  thorpej 	sc.m1 = m1;
    374       1.1  thorpej 	sc.d = d;
    375       1.1  thorpej 	sc.m2 = m2;
    376       1.1  thorpej 
    377       1.1  thorpej 	if (error == 0)
    378       1.1  thorpej 		error = qop_hfsc_add_class(NULL, class_name, ifinfo, parent,
    379       1.1  thorpej 					   &sc, qlimit, flags);
    380       1.1  thorpej 	if (error != 0)
    381       1.1  thorpej 		LOG(LOG_ERR, errno,
    382       1.4   itojun 		    "hfsc: %s: can't add class '%s' on interface '%s'",
    383       1.1  thorpej 		    qoperror(error), class_name, ifname);
    384       1.1  thorpej 	return (error);
    385       1.1  thorpej }
    386       1.1  thorpej 
    387       1.1  thorpej int
    388       1.1  thorpej qcmd_hfsc_modify_class(const char *ifname, const char *class_name,
    389       1.1  thorpej 		       u_int m1, u_int d, u_int m2, int sctype)
    390       1.1  thorpej {
    391       1.1  thorpej 	struct ifinfo *ifinfo;
    392       1.1  thorpej 	struct classinfo *clinfo;
    393       1.1  thorpej 	struct service_curve sc;
    394       1.1  thorpej 
    395       1.1  thorpej 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
    396       1.1  thorpej 		return (QOPERR_BADIF);
    397       1.1  thorpej 
    398       1.1  thorpej 	if ((clinfo = clname2clinfo(ifinfo, class_name)) == NULL)
    399       1.1  thorpej 		return (QOPERR_BADCLASS);
    400       1.1  thorpej 
    401       1.1  thorpej 	sc.m1 = m1;
    402       1.1  thorpej 	sc.d = d;
    403       1.1  thorpej 	sc.m2 = m2;
    404  1.7.12.1    peter 
    405       1.1  thorpej 	return qop_hfsc_modify_class(clinfo, &sc, sctype);
    406       1.1  thorpej }
    407       1.1  thorpej 
    408       1.1  thorpej /*
    409       1.1  thorpej  * qop api
    410       1.1  thorpej  */
    411       1.1  thorpej int
    412       1.1  thorpej qop_hfsc_add_if(struct ifinfo **rp, const char *ifname,
    413       1.1  thorpej 		u_int bandwidth, int flags)
    414       1.1  thorpej {
    415       1.1  thorpej 	struct ifinfo *ifinfo = NULL;
    416       1.1  thorpej 	struct hfsc_ifinfo *hfsc_ifinfo = NULL;
    417       1.1  thorpej 	struct service_curve sc;
    418       1.1  thorpej 	int error;
    419       1.1  thorpej 
    420       1.1  thorpej 	if ((hfsc_ifinfo = calloc(1, sizeof(*hfsc_ifinfo))) == NULL)
    421       1.1  thorpej 		return (QOPERR_NOMEM);
    422       1.1  thorpej 
    423       1.1  thorpej 	error = qop_add_if(&ifinfo, ifname, bandwidth,
    424       1.1  thorpej 			   &hfsc_qdisc, hfsc_ifinfo);
    425       1.1  thorpej 	if (error != 0)
    426       1.1  thorpej 		goto err_ret;
    427       1.1  thorpej 
    428       1.1  thorpej 	/* set enable hook */
    429       1.1  thorpej 	ifinfo->enable_hook = qop_hfsc_enable_hook;
    430       1.1  thorpej 
    431  1.7.12.1    peter 	/* create root class */
    432       1.1  thorpej 	sc.m1 = bandwidth;
    433       1.1  thorpej 	sc.d = 0;
    434       1.1  thorpej 	sc.m2 = bandwidth;
    435       1.1  thorpej 	if ((error = qop_hfsc_add_class(&hfsc_ifinfo->root_class, "root",
    436       1.1  thorpej 					ifinfo, NULL, &sc, 0, 0)) != 0) {
    437       1.1  thorpej 		LOG(LOG_ERR, errno,
    438       1.4   itojun 		    "hfsc: %s: can't create dummy root class on %s!",
    439       1.1  thorpej 		    qoperror(error), ifname);
    440       1.1  thorpej 		(void)qop_delete_if(ifinfo);
    441       1.1  thorpej 		return (QOPERR_CLASS);
    442       1.1  thorpej 	}
    443       1.1  thorpej 
    444       1.1  thorpej 	if (rp != NULL)
    445       1.1  thorpej 		*rp = ifinfo;
    446       1.1  thorpej 	return (0);
    447       1.1  thorpej 
    448       1.1  thorpej  err_ret:
    449       1.1  thorpej 	if (hfsc_ifinfo != NULL) {
    450       1.1  thorpej 		free(hfsc_ifinfo);
    451       1.1  thorpej 		if (ifinfo != NULL)
    452       1.1  thorpej 			ifinfo->private = NULL;
    453       1.1  thorpej 	}
    454       1.1  thorpej 	return (error);
    455       1.1  thorpej }
    456       1.1  thorpej 
    457       1.1  thorpej #define is_sc_null(sc)	(((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0))
    458       1.1  thorpej 
    459       1.1  thorpej int
    460       1.1  thorpej qop_hfsc_add_class(struct classinfo **rp, const char *class_name,
    461       1.1  thorpej 		   struct ifinfo *ifinfo, struct classinfo *parent,
    462       1.1  thorpej 		   struct service_curve *sc, int qlimit, int flags)
    463       1.1  thorpej {
    464       1.1  thorpej 	struct classinfo *clinfo;
    465       1.1  thorpej 	struct hfsc_ifinfo *hfsc_ifinfo;
    466       1.1  thorpej 	struct hfsc_classinfo *hfsc_clinfo = NULL, *parent_clinfo = NULL;
    467       1.1  thorpej 	int error;
    468       1.1  thorpej 
    469       1.1  thorpej 	hfsc_ifinfo = ifinfo->private;
    470       1.1  thorpej 	if ((flags & HFCF_DEFAULTCLASS) && hfsc_ifinfo->default_class != NULL)
    471       1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    472       1.1  thorpej 
    473       1.1  thorpej 	if (validate_sc(sc) != 0)
    474       1.1  thorpej 		return (QOPERR_INVAL);
    475       1.1  thorpej 
    476       1.1  thorpej 	/* admission control */
    477       1.1  thorpej 	if (parent != NULL && !is_sc_null(sc)) {
    478       1.1  thorpej 		parent_clinfo = parent->private;
    479       1.1  thorpej 		gsc_add_sc(&parent_clinfo->gen_rsc, sc);
    480       1.1  thorpej 		gsc_add_sc(&parent_clinfo->gen_fsc, sc);
    481       1.1  thorpej 		if (!is_gsc_under_sc(&parent_clinfo->gen_rsc,
    482       1.1  thorpej 				     &parent_clinfo->rsc) ||
    483       1.1  thorpej 		    !is_gsc_under_sc(&parent_clinfo->gen_fsc,
    484       1.1  thorpej 				     &parent_clinfo->fsc)) {
    485       1.1  thorpej 			/* admission control failure */
    486       1.1  thorpej 			error = QOPERR_ADMISSION_NOBW;
    487       1.1  thorpej 			goto err_ret;
    488       1.1  thorpej 		}
    489       1.1  thorpej 	}
    490  1.7.12.1    peter 
    491       1.1  thorpej 	if ((hfsc_clinfo = calloc(1, sizeof(*hfsc_clinfo))) == NULL) {
    492       1.1  thorpej 		error = QOPERR_NOMEM;
    493       1.1  thorpej 		goto err_ret;
    494       1.1  thorpej 	}
    495       1.1  thorpej 
    496       1.1  thorpej 	hfsc_clinfo->rsc = *sc;
    497       1.1  thorpej 	hfsc_clinfo->fsc = *sc;
    498       1.1  thorpej 	LIST_INIT(&hfsc_clinfo->gen_rsc);
    499       1.1  thorpej 	LIST_INIT(&hfsc_clinfo->gen_fsc);
    500       1.1  thorpej 	hfsc_clinfo->qlimit = qlimit;
    501       1.1  thorpej 	hfsc_clinfo->flags = flags;
    502       1.1  thorpej 
    503       1.1  thorpej 	if ((error = qop_add_class(&clinfo, class_name, ifinfo, parent,
    504       1.1  thorpej 				   hfsc_clinfo)) != 0)
    505       1.1  thorpej 		goto err_ret;
    506       1.1  thorpej 
    507       1.1  thorpej 	/* set delete hook */
    508       1.1  thorpej 	clinfo->delete_hook = qop_hfsc_delete_class_hook;
    509  1.7.12.1    peter 
    510       1.1  thorpej 	if (flags & HFCF_DEFAULTCLASS)
    511       1.1  thorpej 		hfsc_ifinfo->default_class = clinfo;
    512       1.1  thorpej 
    513       1.1  thorpej 	if (parent == NULL) {
    514       1.1  thorpej 		/*
    515       1.1  thorpej 		 * if this is a root class, reserve 20% of the real-time
    516       1.1  thorpej 		 * bandwidth for safety.
    517       1.1  thorpej 		 * many network cards are not able to saturate the wire,
    518       1.1  thorpej 		 * and if we allocate real-time traffic more than the
    519       1.1  thorpej 		 * maximum sending rate of the card, hfsc is no longer
    520       1.1  thorpej 		 * able to meet the delay bound requirements.
    521       1.1  thorpej 		 */
    522       1.1  thorpej 		hfsc_clinfo->rsc.m1 = hfsc_clinfo->rsc.m1 / 10 * 8;
    523       1.1  thorpej 		hfsc_clinfo->rsc.m2 = hfsc_clinfo->rsc.m2 / 10 * 8;
    524       1.1  thorpej 	}
    525       1.1  thorpej 
    526       1.1  thorpej 	if (rp != NULL)
    527       1.1  thorpej 		*rp = clinfo;
    528       1.1  thorpej 	return (0);
    529       1.1  thorpej 
    530       1.1  thorpej  err_ret:
    531       1.1  thorpej 	/* cancel admission control */
    532       1.1  thorpej 	if (parent != NULL && !is_sc_null(sc)) {
    533       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_rsc, sc);
    534       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_fsc, sc);
    535       1.1  thorpej 	}
    536       1.1  thorpej 
    537       1.1  thorpej 	if (hfsc_clinfo != NULL) {
    538       1.1  thorpej 		free(hfsc_clinfo);
    539       1.1  thorpej 		clinfo->private = NULL;
    540       1.1  thorpej 	}
    541  1.7.12.1    peter 
    542       1.1  thorpej 	return (error);
    543       1.1  thorpej }
    544       1.1  thorpej 
    545       1.1  thorpej /*
    546       1.1  thorpej  * this is called from qop_delete_class() before a class is destroyed
    547       1.1  thorpej  * for discipline specific cleanup.
    548       1.1  thorpej  */
    549       1.1  thorpej static int
    550       1.1  thorpej qop_hfsc_delete_class_hook(struct classinfo *clinfo)
    551       1.1  thorpej {
    552       1.1  thorpej 	struct hfsc_classinfo *hfsc_clinfo, *parent_clinfo;
    553       1.1  thorpej 
    554       1.1  thorpej 	hfsc_clinfo = clinfo->private;
    555  1.7.12.1    peter 
    556       1.1  thorpej 	/* cancel admission control */
    557       1.1  thorpej 	if (clinfo->parent != NULL) {
    558       1.1  thorpej 		parent_clinfo = clinfo->parent->private;
    559       1.1  thorpej 
    560       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_rsc, &hfsc_clinfo->rsc);
    561       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_fsc, &hfsc_clinfo->fsc);
    562       1.1  thorpej 	}
    563       1.1  thorpej 
    564       1.1  thorpej 	gsc_destroy(&hfsc_clinfo->gen_rsc);
    565       1.1  thorpej 	gsc_destroy(&hfsc_clinfo->gen_fsc);
    566       1.1  thorpej 	return (0);
    567       1.1  thorpej }
    568       1.1  thorpej 
    569       1.1  thorpej int
    570       1.1  thorpej qop_hfsc_modify_class(struct classinfo *clinfo,
    571       1.1  thorpej 		      struct service_curve *sc, int sctype)
    572       1.1  thorpej {
    573       1.1  thorpej 	struct hfsc_classinfo *hfsc_clinfo, *parent_clinfo;
    574  1.7.12.1    peter 	struct service_curve rsc, fsc, usc;
    575       1.1  thorpej 	int error;
    576       1.1  thorpej 
    577       1.1  thorpej 	if (validate_sc(sc) != 0)
    578       1.1  thorpej 		return (QOPERR_INVAL);
    579       1.1  thorpej 
    580       1.1  thorpej 	hfsc_clinfo = clinfo->private;
    581       1.1  thorpej 	if (clinfo->parent == NULL)
    582       1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    583       1.1  thorpej 	parent_clinfo = clinfo->parent->private;
    584       1.1  thorpej 
    585       1.1  thorpej 	/* save old service curves */
    586       1.1  thorpej 	rsc = hfsc_clinfo->rsc;
    587       1.1  thorpej 	fsc = hfsc_clinfo->fsc;
    588  1.7.12.1    peter 	usc = hfsc_clinfo->usc;
    589       1.1  thorpej 
    590       1.1  thorpej 	/* admission control */
    591       1.1  thorpej 	if (sctype & HFSC_REALTIMESC) {
    592  1.7.12.1    peter 		/* if the class has usc, rsc should be smaller than usc */
    593  1.7.12.1    peter 		if (!is_sc_null(&hfsc_clinfo->usc)) {
    594  1.7.12.1    peter 			gsc_head_t tmp_gen_rsc =
    595  1.7.12.1    peter 			    LIST_HEAD_INITIALIZER(tmp_gen_rsc);
    596  1.7.12.1    peter 
    597  1.7.12.1    peter 			gsc_add_sc(&tmp_gen_rsc, sc);
    598  1.7.12.1    peter 			if (!is_gsc_under_sc(&tmp_gen_rsc, &hfsc_clinfo->usc)) {
    599  1.7.12.1    peter 				gsc_destroy(&tmp_gen_rsc);
    600  1.7.12.1    peter 				return (QOPERR_ADMISSION);
    601  1.7.12.1    peter 			}
    602  1.7.12.1    peter 			gsc_destroy(&tmp_gen_rsc);
    603  1.7.12.1    peter 		}
    604  1.7.12.1    peter 
    605       1.1  thorpej 		if (!is_gsc_under_sc(&hfsc_clinfo->gen_rsc, sc)) {
    606       1.1  thorpej 			/* admission control failure */
    607       1.1  thorpej 			return (QOPERR_ADMISSION);
    608       1.1  thorpej 		}
    609  1.7.12.1    peter 
    610       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_rsc, &hfsc_clinfo->rsc);
    611       1.1  thorpej 		gsc_add_sc(&parent_clinfo->gen_rsc, sc);
    612       1.1  thorpej 		if (!is_gsc_under_sc(&parent_clinfo->gen_rsc,
    613       1.1  thorpej 				     &parent_clinfo->rsc)) {
    614       1.1  thorpej 			/* admission control failure */
    615       1.1  thorpej 			gsc_sub_sc(&parent_clinfo->gen_rsc, sc);
    616       1.1  thorpej 			gsc_add_sc(&parent_clinfo->gen_rsc, &hfsc_clinfo->rsc);
    617       1.1  thorpej 			return (QOPERR_ADMISSION_NOBW);
    618       1.1  thorpej 		}
    619       1.1  thorpej 		hfsc_clinfo->rsc = *sc;
    620       1.1  thorpej 	}
    621       1.1  thorpej 	if (sctype & HFSC_LINKSHARINGSC) {
    622       1.1  thorpej 		if (!is_gsc_under_sc(&hfsc_clinfo->gen_fsc, sc)) {
    623       1.1  thorpej 			/* admission control failure */
    624       1.1  thorpej 			return (QOPERR_ADMISSION);
    625       1.1  thorpej 		}
    626  1.7.12.1    peter 
    627       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_fsc, &hfsc_clinfo->fsc);
    628       1.1  thorpej 		gsc_add_sc(&parent_clinfo->gen_fsc, sc);
    629       1.1  thorpej 		if (!is_gsc_under_sc(&parent_clinfo->gen_fsc,
    630       1.1  thorpej 				     &parent_clinfo->fsc)) {
    631       1.1  thorpej 			/* admission control failure */
    632       1.1  thorpej 			gsc_sub_sc(&parent_clinfo->gen_fsc, sc);
    633       1.1  thorpej 			gsc_add_sc(&parent_clinfo->gen_fsc, &hfsc_clinfo->fsc);
    634       1.1  thorpej 			return (QOPERR_ADMISSION_NOBW);
    635       1.1  thorpej 		}
    636       1.1  thorpej 		hfsc_clinfo->fsc = *sc;
    637       1.1  thorpej 	}
    638  1.7.12.1    peter 	if (sctype & HFSC_UPPERLIMITSC) {
    639  1.7.12.1    peter 		if (!is_sc_null(sc)) {
    640  1.7.12.1    peter 			/* usc must be smaller than interface bandwidth */
    641  1.7.12.1    peter 			struct classinfo *root_clinfo =
    642  1.7.12.1    peter 			    clname2clinfo(clinfo->ifinfo, "root");
    643  1.7.12.1    peter 			if (root_clinfo != NULL) {
    644  1.7.12.1    peter 				struct hfsc_classinfo *root_hfsc_clinfo =
    645  1.7.12.1    peter 				    root_clinfo->private;
    646  1.7.12.1    peter 				if (!is_sc_null(&root_hfsc_clinfo->rsc)) {
    647  1.7.12.1    peter 					gsc_head_t tmp_gen_usc =
    648  1.7.12.1    peter 					    LIST_HEAD_INITIALIZER(tmp_gen_usc);
    649  1.7.12.1    peter 					gsc_add_sc(&tmp_gen_usc, sc);
    650  1.7.12.1    peter 					if (!is_gsc_under_sc(&tmp_gen_usc,
    651  1.7.12.1    peter 					    &root_hfsc_clinfo->fsc)) {
    652  1.7.12.1    peter 						/* illegal attempt to set
    653  1.7.12.1    peter 						   upper limit curve to be
    654  1.7.12.1    peter 						   greater than the interface
    655  1.7.12.1    peter 						   bandwidth */
    656  1.7.12.1    peter 						gsc_destroy(&tmp_gen_usc);
    657  1.7.12.1    peter 						return (QOPERR_ADMISSION);
    658  1.7.12.1    peter 					}
    659  1.7.12.1    peter 					gsc_destroy(&tmp_gen_usc);
    660  1.7.12.1    peter 				}
    661  1.7.12.1    peter 			}
    662  1.7.12.1    peter 			/* if this class has rsc, check that usc >= rsc */
    663  1.7.12.1    peter 			if (!is_sc_null(&hfsc_clinfo->rsc)) {
    664  1.7.12.1    peter 				gsc_head_t tmp_gen_rsc =
    665  1.7.12.1    peter 				    LIST_HEAD_INITIALIZER(tmp_gen_rsc);
    666  1.7.12.1    peter 				gsc_add_sc(&tmp_gen_rsc, &hfsc_clinfo->rsc);
    667  1.7.12.1    peter 				if (!is_gsc_under_sc(&tmp_gen_rsc, sc)) {
    668  1.7.12.1    peter 					/* illegal attempt to set upper limit
    669  1.7.12.1    peter 					   curve to be under the real-time
    670  1.7.12.1    peter 					   service curve */
    671  1.7.12.1    peter 					gsc_destroy(&tmp_gen_rsc);
    672  1.7.12.1    peter 					return (QOPERR_ADMISSION);
    673  1.7.12.1    peter 				}
    674  1.7.12.1    peter 				gsc_destroy(&tmp_gen_rsc);
    675  1.7.12.1    peter 			}
    676  1.7.12.1    peter 		}
    677  1.7.12.1    peter 		hfsc_clinfo->usc = *sc;
    678  1.7.12.1    peter 	}
    679       1.1  thorpej 
    680       1.1  thorpej 	error = qop_modify_class(clinfo, (void *)((long)sctype));
    681       1.1  thorpej 	if (error == 0)
    682       1.1  thorpej 		return (0);
    683       1.1  thorpej 
    684       1.1  thorpej 	/* modify failed!, restore the old service curves */
    685       1.1  thorpej 	if (sctype & HFSC_REALTIMESC) {
    686       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_rsc, sc);
    687       1.1  thorpej 		gsc_add_sc(&parent_clinfo->gen_rsc, &rsc);
    688       1.1  thorpej 		hfsc_clinfo->rsc = rsc;
    689       1.1  thorpej 	}
    690       1.1  thorpej 	if (sctype & HFSC_LINKSHARINGSC) {
    691       1.1  thorpej 		gsc_sub_sc(&parent_clinfo->gen_fsc, sc);
    692       1.1  thorpej 		gsc_add_sc(&parent_clinfo->gen_fsc, &fsc);
    693       1.1  thorpej 		hfsc_clinfo->fsc = fsc;
    694       1.1  thorpej 	}
    695  1.7.12.1    peter 	if (sctype & HFSC_UPPERLIMITSC) {
    696  1.7.12.1    peter 		hfsc_clinfo->usc = usc;
    697  1.7.12.1    peter 	}
    698       1.1  thorpej 	return (error);
    699       1.1  thorpej }
    700       1.1  thorpej 
    701       1.1  thorpej /*
    702       1.1  thorpej  * sanity check at enabling hfsc:
    703       1.1  thorpej  *  1. there must one default class for an interface
    704       1.1  thorpej  *  2. the default class must be a leaf class
    705       1.1  thorpej  *  3. an internal class should not have filters
    706       1.1  thorpej  * (rule 2 and 3 are due to the fact that the hfsc link-sharing algorithm
    707       1.1  thorpej  *  do not schedule internal classes.)
    708       1.1  thorpej  */
    709       1.1  thorpej static int
    710       1.1  thorpej qop_hfsc_enable_hook(struct ifinfo *ifinfo)
    711       1.1  thorpej {
    712       1.1  thorpej 	struct hfsc_ifinfo *hfsc_ifinfo;
    713       1.1  thorpej 	struct classinfo *clinfo;
    714  1.7.12.1    peter 
    715       1.1  thorpej 	hfsc_ifinfo = ifinfo->private;
    716       1.1  thorpej 	if (hfsc_ifinfo->default_class == NULL) {
    717       1.4   itojun 		LOG(LOG_ERR, 0, "hfsc: no default class on interface %s!",
    718       1.1  thorpej 		    ifinfo->ifname);
    719       1.1  thorpej 		return (QOPERR_CLASS);
    720       1.1  thorpej 	} else if (hfsc_ifinfo->default_class->child != NULL) {
    721       1.4   itojun 		LOG(LOG_ERR, 0, "hfsc: default class on %s must be a leaf!",
    722       1.1  thorpej 		    ifinfo->ifname);
    723       1.1  thorpej 		return (QOPERR_CLASS);
    724       1.1  thorpej 	}
    725       1.1  thorpej 
    726       1.1  thorpej 	LIST_FOREACH(clinfo, &ifinfo->cllist, next) {
    727       1.1  thorpej 		if (clinfo->child != NULL && !LIST_EMPTY(&clinfo->fltrlist)) {
    728       1.4   itojun 			LOG(LOG_ERR, 0,
    729       1.4   itojun 			    "hfsc: internal class \"%s\" should not have a filter!",
    730       1.1  thorpej 			    clinfo->clname);
    731       1.1  thorpej 			return (QOPERR_CLASS);
    732       1.1  thorpej 		}
    733       1.1  thorpej 	}
    734       1.1  thorpej 
    735       1.1  thorpej 	return (0);
    736       1.1  thorpej }
    737       1.1  thorpej 
    738       1.1  thorpej static int
    739       1.1  thorpej validate_sc(struct service_curve *sc)
    740       1.1  thorpej {
    741       1.1  thorpej 	/* the 1st segment of a concave curve must be zero */
    742       1.1  thorpej 	if (sc->m1 < sc->m2 && sc->m1 != 0) {
    743       1.4   itojun 		LOG(LOG_ERR, 0, "m1 must be 0 for convex!");
    744       1.1  thorpej 		return (-1);
    745       1.1  thorpej 	}
    746  1.7.12.1    peter 	if (sc->m1 > sc->m2 && sc->m2 == 0) {
    747  1.7.12.1    peter 		LOG(LOG_ERR, 0, "m2 must be nonzero for concave!");
    748  1.7.12.1    peter 		return (-1);
    749  1.7.12.1    peter 	}
    750       1.1  thorpej 	return (0);
    751       1.1  thorpej }
    752       1.1  thorpej 
    753       1.1  thorpej /*
    754       1.1  thorpej  * admission control using generalized service curve
    755       1.1  thorpej  */
    756  1.7.12.1    peter #ifndef INFINITY
    757  1.7.12.1    peter #define	INFINITY	HUGE_VAL  /* positive infinity defined in <math.h> */
    758  1.7.12.1    peter #endif
    759       1.1  thorpej 
    760       1.1  thorpej /* add a new service curve to a generilized service curve */
    761       1.1  thorpej static void
    762       1.1  thorpej gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc)
    763       1.1  thorpej {
    764       1.1  thorpej 	if (is_sc_null(sc))
    765       1.1  thorpej 		return;
    766       1.1  thorpej 	if (sc->d != 0)
    767       1.1  thorpej 		gsc_add_seg(gsc, 0, 0, (double)sc->d, (double)sc->m1);
    768  1.7.12.1    peter 	gsc_add_seg(gsc, (double)sc->d, 0, INFINITY, (double)sc->m2);
    769       1.1  thorpej }
    770       1.1  thorpej 
    771       1.1  thorpej /* subtract a service curve from a generilized service curve */
    772       1.1  thorpej static void
    773       1.1  thorpej gsc_sub_sc(struct gen_sc *gsc, struct service_curve *sc)
    774       1.1  thorpej {
    775       1.1  thorpej 	if (is_sc_null(sc))
    776       1.1  thorpej 		return;
    777       1.1  thorpej 	if (sc->d != 0)
    778       1.1  thorpej 		gsc_sub_seg(gsc, 0, 0, (double)sc->d, (double)sc->m1);
    779  1.7.12.1    peter 	gsc_sub_seg(gsc, (double)sc->d, 0, INFINITY, (double)sc->m2);
    780       1.1  thorpej }
    781       1.1  thorpej 
    782       1.1  thorpej /*
    783       1.1  thorpej  * check whether all points of a generalized service curve have
    784       1.1  thorpej  * their y-coordinates no larger than a given two-piece linear
    785       1.1  thorpej  * service curve.
    786       1.1  thorpej  */
    787       1.1  thorpej static int
    788       1.1  thorpej is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc)
    789       1.1  thorpej {
    790       1.1  thorpej 	struct segment *s, *last, *end;
    791       1.1  thorpej 	double y;
    792       1.1  thorpej 
    793       1.1  thorpej 	if (is_sc_null(sc)) {
    794       1.1  thorpej 		if (LIST_EMPTY(gsc))
    795       1.1  thorpej 			return (1);
    796       1.1  thorpej 		LIST_FOREACH(s, gsc, _next) {
    797       1.1  thorpej 			if (s->m != 0)
    798       1.1  thorpej 				return (0);
    799       1.1  thorpej 		}
    800       1.1  thorpej 		return (1);
    801       1.1  thorpej 	}
    802       1.1  thorpej 	/*
    803  1.7.12.1    peter 	 * gsc has a dummy entry at the end with x = INFINITY.
    804       1.1  thorpej 	 * loop through up to this dummy entry.
    805       1.1  thorpej 	 */
    806  1.7.12.1    peter 	end = gsc_getentry(gsc, INFINITY);
    807       1.1  thorpej 	if (end == NULL)
    808       1.1  thorpej 		return (1);
    809       1.1  thorpej 	last = NULL;
    810       1.1  thorpej 	for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) {
    811       1.1  thorpej 		if (s->y > sc_x2y(sc, s->x))
    812       1.1  thorpej 			return (0);
    813       1.1  thorpej 		last = s;
    814       1.1  thorpej 	}
    815       1.1  thorpej 	/* last now holds the real last segment */
    816       1.1  thorpej 	if (last == NULL)
    817       1.1  thorpej 		return (1);
    818       1.1  thorpej 	if (last->m > sc->m2)
    819       1.1  thorpej 		return (0);
    820       1.1  thorpej 	if (last->x < sc->d && last->m > sc->m1) {
    821       1.1  thorpej 		y = last->y + (sc->d - last->x) * last->m;
    822       1.1  thorpej 		if (y > sc_x2y(sc, sc->d))
    823       1.1  thorpej 			return (0);
    824       1.1  thorpej 	}
    825       1.1  thorpej 	return (1);
    826       1.1  thorpej }
    827       1.1  thorpej 
    828       1.1  thorpej static void
    829       1.1  thorpej gsc_destroy(struct gen_sc *gsc)
    830       1.1  thorpej {
    831       1.1  thorpej 	struct segment *s;
    832       1.1  thorpej 
    833       1.1  thorpej 	while ((s = LIST_FIRST(gsc)) != NULL) {
    834       1.1  thorpej 		LIST_REMOVE(s, _next);
    835       1.1  thorpej 		free(s);
    836       1.1  thorpej 	}
    837       1.1  thorpej }
    838       1.1  thorpej 
    839       1.1  thorpej /*
    840       1.1  thorpej  * return a segment entry starting at x.
    841       1.1  thorpej  * if gsc has no entry starting at x, a new entry is created at x.
    842       1.1  thorpej  */
    843       1.1  thorpej static struct segment *
    844       1.1  thorpej gsc_getentry(struct gen_sc *gsc, double x)
    845       1.1  thorpej {
    846       1.1  thorpej 	struct segment *new, *prev, *s;
    847       1.1  thorpej 
    848       1.1  thorpej 	prev = NULL;
    849       1.1  thorpej 	LIST_FOREACH(s, gsc, _next) {
    850       1.1  thorpej 		if (s->x == x)
    851       1.1  thorpej 			return (s);	/* matching entry found */
    852       1.1  thorpej 		else if (s->x < x)
    853       1.1  thorpej 			prev = s;
    854       1.1  thorpej 		else
    855       1.1  thorpej 			break;
    856       1.1  thorpej 	}
    857       1.1  thorpej 
    858       1.1  thorpej 	/* we have to create a new entry */
    859       1.1  thorpej 	if ((new = calloc(1, sizeof(struct segment))) == NULL)
    860       1.1  thorpej 		return (NULL);
    861       1.1  thorpej 
    862       1.1  thorpej 	new->x = x;
    863  1.7.12.1    peter 	if (x == INFINITY || s == NULL)
    864       1.1  thorpej 		new->d = 0;
    865  1.7.12.1    peter 	else if (s->x == INFINITY)
    866  1.7.12.1    peter 		new->d = INFINITY;
    867       1.1  thorpej 	else
    868       1.1  thorpej 		new->d = s->x - x;
    869       1.1  thorpej 	if (prev == NULL) {
    870       1.1  thorpej 		/* insert the new entry at the head of the list */
    871       1.1  thorpej 		new->y = 0;
    872       1.1  thorpej 		new->m = 0;
    873       1.1  thorpej 		LIST_INSERT_HEAD(gsc, new, _next);
    874       1.1  thorpej 	} else {
    875       1.1  thorpej 		/*
    876       1.1  thorpej 		 * the start point intersects with the segment pointed by
    877       1.1  thorpej 		 * prev.  divide prev into 2 segments
    878       1.1  thorpej 		 */
    879  1.7.12.1    peter 		if (x == INFINITY) {
    880  1.7.12.1    peter 			prev->d = INFINITY;
    881       1.1  thorpej 			if (prev->m == 0)
    882       1.1  thorpej 				new->y = prev->y;
    883       1.1  thorpej 			else
    884  1.7.12.1    peter 				new->y = INFINITY;
    885       1.1  thorpej 		} else {
    886       1.1  thorpej 			prev->d = x - prev->x;
    887       1.1  thorpej 			new->y = prev->d * prev->m + prev->y;
    888       1.1  thorpej 		}
    889       1.1  thorpej 		new->m = prev->m;
    890       1.1  thorpej 		LIST_INSERT_AFTER(prev, new, _next);
    891       1.1  thorpej 	}
    892       1.1  thorpej 	return (new);
    893       1.1  thorpej }
    894       1.1  thorpej 
    895       1.1  thorpej /* add a segment to a generalized service curve */
    896       1.1  thorpej static int
    897       1.1  thorpej gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
    898       1.1  thorpej {
    899       1.1  thorpej 	struct segment *start, *end, *s;
    900       1.1  thorpej 	double x2;
    901       1.1  thorpej 
    902  1.7.12.1    peter 	if (d == INFINITY)
    903  1.7.12.1    peter 		x2 = INFINITY;
    904       1.1  thorpej 	else
    905       1.1  thorpej 		x2 = x + d;
    906       1.1  thorpej 	start = gsc_getentry(gsc, x);
    907       1.1  thorpej 	end   = gsc_getentry(gsc, x2);
    908       1.1  thorpej 	if (start == NULL || end == NULL)
    909       1.1  thorpej 		return (-1);
    910       1.1  thorpej 
    911       1.1  thorpej 	for (s = start; s != end; s = LIST_NEXT(s, _next)) {
    912       1.1  thorpej 		s->m += m;
    913       1.1  thorpej 		s->y += y + (s->x - x) * m;
    914       1.1  thorpej 	}
    915       1.1  thorpej 
    916  1.7.12.1    peter 	end = gsc_getentry(gsc, INFINITY);
    917       1.1  thorpej 	for (; s != end; s = LIST_NEXT(s, _next)) {
    918       1.1  thorpej 		s->y += m * d;
    919       1.1  thorpej 	}
    920       1.1  thorpej 
    921       1.1  thorpej 	return (0);
    922       1.1  thorpej }
    923       1.1  thorpej 
    924       1.1  thorpej /* subtract a segment from a generalized service curve */
    925       1.1  thorpej static int
    926       1.1  thorpej gsc_sub_seg(struct gen_sc *gsc, double x, double y, double d, double m)
    927       1.1  thorpej {
    928       1.1  thorpej 	if (gsc_add_seg(gsc, x, y, d, -m) < 0)
    929       1.1  thorpej 		return (-1);
    930       1.1  thorpej 	gsc_compress(gsc);
    931       1.1  thorpej 	return (0);
    932       1.1  thorpej }
    933       1.1  thorpej 
    934       1.1  thorpej /*
    935       1.1  thorpej  * collapse adjacent segments with the same slope
    936       1.1  thorpej  */
    937       1.1  thorpej static void
    938       1.1  thorpej gsc_compress(struct gen_sc *gsc)
    939       1.1  thorpej {
    940       1.1  thorpej 	struct segment *s, *next;
    941       1.1  thorpej 
    942       1.1  thorpej  again:
    943       1.1  thorpej 	LIST_FOREACH(s, gsc, _next) {
    944       1.1  thorpej 
    945       1.1  thorpej 		if ((next = LIST_NEXT(s, _next)) == NULL) {
    946       1.1  thorpej 			if (LIST_FIRST(gsc) == s && s->m == 0) {
    947       1.1  thorpej 				/*
    948       1.1  thorpej 				 * if this is the only entry and its
    949       1.1  thorpej 				 * slope is 0, it's a remaining dummy
    950       1.1  thorpej 				 * entry. we can discard it.
    951       1.1  thorpej 				 */
    952       1.1  thorpej 				LIST_REMOVE(s, _next);
    953       1.1  thorpej 				free(s);
    954       1.1  thorpej 			}
    955       1.1  thorpej 			break;
    956       1.1  thorpej 		}
    957       1.1  thorpej 
    958       1.1  thorpej 		if (s->x == next->x) {
    959       1.1  thorpej 			/* discard this entry */
    960       1.1  thorpej 			LIST_REMOVE(s, _next);
    961       1.1  thorpej 			free(s);
    962       1.1  thorpej 			goto again;
    963       1.1  thorpej 		} else if (s->m == next->m) {
    964       1.1  thorpej 			/* join the two entries */
    965  1.7.12.1    peter 			if (s->d != INFINITY && next->d != INFINITY)
    966       1.1  thorpej 				s->d += next->d;
    967       1.1  thorpej 			LIST_REMOVE(next, _next);
    968       1.1  thorpej 			free(next);
    969       1.1  thorpej 			goto again;
    970       1.1  thorpej 		}
    971       1.1  thorpej 	}
    972       1.1  thorpej }
    973       1.1  thorpej 
    974       1.1  thorpej /* get y-projection of a service curve */
    975       1.1  thorpej static double
    976       1.1  thorpej sc_x2y(struct service_curve *sc, double x)
    977       1.1  thorpej {
    978       1.1  thorpej 	double y;
    979       1.1  thorpej 
    980       1.1  thorpej 	if (x <= (double)sc->d)
    981       1.1  thorpej 		/* y belongs to the 1st segment */
    982       1.1  thorpej 		y = x * (double)sc->m1;
    983       1.1  thorpej 	else
    984       1.1  thorpej 		/* y belongs to the 2nd segment */
    985       1.1  thorpej 		y = (double)sc->d * (double)sc->m1
    986       1.1  thorpej 			+ (x - (double)sc->d) * (double)sc->m2;
    987       1.1  thorpej 	return (y);
    988       1.1  thorpej }
    989       1.1  thorpej 
    990       1.1  thorpej /*
    991       1.1  thorpej  *  system call interfaces for qdisc_ops
    992       1.1  thorpej  */
    993       1.1  thorpej static int
    994       1.1  thorpej hfsc_attach(struct ifinfo *ifinfo)
    995       1.1  thorpej {
    996       1.1  thorpej 	struct hfsc_attach attach;
    997       1.1  thorpej 
    998       1.1  thorpej 	if (hfsc_fd < 0 &&
    999       1.1  thorpej 	    (hfsc_fd = open(HFSC_DEVICE, O_RDWR)) < 0 &&
   1000       1.1  thorpej 	    (hfsc_fd = open_module(HFSC_DEVICE, O_RDWR)) < 0) {
   1001       1.4   itojun 		LOG(LOG_ERR, errno, "HFSC open");
   1002       1.1  thorpej 		return (QOPERR_SYSCALL);
   1003       1.1  thorpej 	}
   1004       1.1  thorpej 
   1005       1.1  thorpej 	hfsc_refcount++;
   1006       1.1  thorpej 	memset(&attach, 0, sizeof(attach));
   1007       1.1  thorpej 	strncpy(attach.iface.hfsc_ifname, ifinfo->ifname, IFNAMSIZ);
   1008       1.1  thorpej 	attach.bandwidth = ifinfo->bandwidth;
   1009       1.1  thorpej 
   1010       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_IF_ATTACH, &attach) < 0)
   1011       1.1  thorpej 		return (QOPERR_SYSCALL);
   1012       1.1  thorpej 	return (0);
   1013       1.1  thorpej }
   1014       1.1  thorpej 
   1015       1.1  thorpej static int
   1016       1.1  thorpej hfsc_detach(struct ifinfo *ifinfo)
   1017       1.1  thorpej {
   1018       1.1  thorpej 	struct hfsc_interface iface;
   1019  1.7.12.1    peter 
   1020       1.1  thorpej 	memset(&iface, 0, sizeof(iface));
   1021       1.1  thorpej 	strncpy(iface.hfsc_ifname, ifinfo->ifname, IFNAMSIZ);
   1022       1.1  thorpej 
   1023       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_IF_DETACH, &iface) < 0)
   1024       1.1  thorpej 		return (QOPERR_SYSCALL);
   1025       1.1  thorpej 
   1026       1.1  thorpej 	if (--hfsc_refcount == 0) {
   1027       1.1  thorpej 		close(hfsc_fd);
   1028       1.1  thorpej 		hfsc_fd = -1;
   1029       1.1  thorpej 	}
   1030       1.1  thorpej 	return (0);
   1031       1.1  thorpej }
   1032       1.1  thorpej 
   1033       1.1  thorpej static int
   1034       1.1  thorpej hfsc_clear(struct ifinfo *ifinfo)
   1035       1.1  thorpej {
   1036       1.1  thorpej 	struct hfsc_interface iface;
   1037       1.1  thorpej 
   1038       1.1  thorpej 	memset(&iface, 0, sizeof(iface));
   1039       1.1  thorpej 	strncpy(iface.hfsc_ifname, ifinfo->ifname, IFNAMSIZ);
   1040       1.1  thorpej 
   1041       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_CLEAR_HIERARCHY, &iface) < 0)
   1042       1.1  thorpej 		return (QOPERR_SYSCALL);
   1043       1.1  thorpej 	return (0);
   1044       1.1  thorpej }
   1045       1.1  thorpej 
   1046       1.1  thorpej static int
   1047       1.1  thorpej hfsc_enable(struct ifinfo *ifinfo)
   1048       1.1  thorpej {
   1049       1.1  thorpej 	struct hfsc_interface iface;
   1050       1.1  thorpej 
   1051       1.1  thorpej 	memset(&iface, 0, sizeof(iface));
   1052       1.1  thorpej 	strncpy(iface.hfsc_ifname, ifinfo->ifname, IFNAMSIZ);
   1053       1.1  thorpej 
   1054       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_ENABLE, &iface) < 0)
   1055       1.1  thorpej 		return (QOPERR_SYSCALL);
   1056       1.1  thorpej 	return (0);
   1057       1.1  thorpej }
   1058       1.1  thorpej 
   1059       1.1  thorpej static int
   1060       1.1  thorpej hfsc_disable(struct ifinfo *ifinfo)
   1061       1.1  thorpej {
   1062       1.1  thorpej 	struct hfsc_interface iface;
   1063       1.1  thorpej 
   1064       1.1  thorpej 	memset(&iface, 0, sizeof(iface));
   1065       1.1  thorpej 	strncpy(iface.hfsc_ifname, ifinfo->ifname, IFNAMSIZ);
   1066       1.1  thorpej 
   1067       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_DISABLE, &iface) < 0)
   1068       1.1  thorpej 		return (QOPERR_SYSCALL);
   1069       1.1  thorpej 	return (0);
   1070       1.1  thorpej }
   1071       1.1  thorpej 
   1072       1.1  thorpej static int
   1073       1.1  thorpej hfsc_add_class(struct classinfo *clinfo)
   1074       1.1  thorpej {
   1075       1.1  thorpej 	struct hfsc_add_class class_add;
   1076       1.1  thorpej 	struct hfsc_classinfo *hfsc_clinfo;
   1077       1.1  thorpej 	struct hfsc_ifinfo *hfsc_ifinfo;
   1078       1.1  thorpej 
   1079       1.1  thorpej 	hfsc_ifinfo = clinfo->ifinfo->private;
   1080       1.1  thorpej 	hfsc_clinfo = clinfo->private;
   1081  1.7.12.1    peter 
   1082       1.1  thorpej 	memset(&class_add, 0, sizeof(class_add));
   1083       1.1  thorpej 	strncpy(class_add.iface.hfsc_ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
   1084  1.7.12.1    peter 
   1085  1.7.12.1    peter 	if (clinfo->parent == NULL)
   1086  1.7.12.1    peter 		class_add.parent_handle = HFSC_NULLCLASS_HANDLE;
   1087       1.1  thorpej 	else
   1088       1.1  thorpej 		class_add.parent_handle = clinfo->parent->handle;
   1089  1.7.12.1    peter 
   1090       1.1  thorpej 	class_add.service_curve = hfsc_clinfo->rsc;
   1091       1.1  thorpej 	class_add.qlimit = hfsc_clinfo->qlimit;
   1092       1.1  thorpej 	class_add.flags = hfsc_clinfo->flags;
   1093  1.7.12.1    peter 
   1094       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_ADD_CLASS, &class_add) < 0) {
   1095       1.1  thorpej 		clinfo->handle = HFSC_NULLCLASS_HANDLE;
   1096       1.1  thorpej 		return (QOPERR_SYSCALL);
   1097       1.1  thorpej 	}
   1098       1.1  thorpej 	clinfo->handle = class_add.class_handle;
   1099       1.1  thorpej 	return (0);
   1100       1.1  thorpej }
   1101       1.1  thorpej 
   1102       1.1  thorpej static int
   1103       1.1  thorpej hfsc_modify_class(struct classinfo *clinfo, void *arg)
   1104       1.1  thorpej {
   1105       1.1  thorpej 	struct hfsc_modify_class class_mod;
   1106       1.1  thorpej 	struct hfsc_classinfo *hfsc_clinfo;
   1107       1.1  thorpej 	long sctype;
   1108       1.1  thorpej 
   1109       1.1  thorpej 	sctype = (long)arg;
   1110       1.1  thorpej 	hfsc_clinfo = clinfo->private;
   1111       1.1  thorpej 
   1112       1.1  thorpej 	memset(&class_mod, 0, sizeof(class_mod));
   1113       1.1  thorpej 	strncpy(class_mod.iface.hfsc_ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
   1114       1.1  thorpej 	class_mod.class_handle = clinfo->handle;
   1115       1.1  thorpej 	if (sctype & HFSC_REALTIMESC)
   1116       1.1  thorpej 		class_mod.service_curve = hfsc_clinfo->rsc;
   1117       1.1  thorpej 	else if (sctype & HFSC_LINKSHARINGSC)
   1118       1.1  thorpej 		class_mod.service_curve = hfsc_clinfo->fsc;
   1119  1.7.12.1    peter 	else if (sctype & HFSC_UPPERLIMITSC)
   1120  1.7.12.1    peter 		class_mod.service_curve = hfsc_clinfo->usc;
   1121       1.1  thorpej 	else
   1122       1.1  thorpej 		return (QOPERR_INVAL);
   1123       1.1  thorpej 	class_mod.sctype = sctype;
   1124       1.1  thorpej 
   1125       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_MOD_CLASS, &class_mod) < 0)
   1126       1.1  thorpej 		return (QOPERR_SYSCALL);
   1127       1.1  thorpej 	return (0);
   1128       1.1  thorpej }
   1129       1.1  thorpej 
   1130       1.1  thorpej static int
   1131       1.1  thorpej hfsc_delete_class(struct classinfo *clinfo)
   1132       1.1  thorpej {
   1133       1.1  thorpej 	struct hfsc_delete_class class_delete;
   1134       1.1  thorpej 
   1135  1.7.12.1    peter 	if (clinfo->handle == HFSC_NULLCLASS_HANDLE)
   1136       1.1  thorpej 		return (0);
   1137       1.1  thorpej 
   1138       1.1  thorpej 	memset(&class_delete, 0, sizeof(class_delete));
   1139       1.1  thorpej 	strncpy(class_delete.iface.hfsc_ifname, clinfo->ifinfo->ifname,
   1140       1.1  thorpej 		IFNAMSIZ);
   1141       1.1  thorpej 	class_delete.class_handle = clinfo->handle;
   1142       1.1  thorpej 
   1143       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_DEL_CLASS, &class_delete) < 0)
   1144       1.1  thorpej 		return (QOPERR_SYSCALL);
   1145       1.1  thorpej 	return (0);
   1146       1.1  thorpej }
   1147       1.1  thorpej 
   1148       1.1  thorpej static int
   1149       1.1  thorpej hfsc_add_filter(struct fltrinfo *fltrinfo)
   1150       1.1  thorpej {
   1151       1.1  thorpej 	struct hfsc_add_filter fltr_add;
   1152  1.7.12.1    peter 
   1153       1.1  thorpej 	memset(&fltr_add, 0, sizeof(fltr_add));
   1154       1.1  thorpej 	strncpy(fltr_add.iface.hfsc_ifname, fltrinfo->clinfo->ifinfo->ifname,
   1155       1.1  thorpej 		IFNAMSIZ);
   1156       1.1  thorpej 	fltr_add.class_handle = fltrinfo->clinfo->handle;
   1157       1.1  thorpej 	fltr_add.filter = fltrinfo->fltr;
   1158       1.1  thorpej 
   1159       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_ADD_FILTER, &fltr_add) < 0)
   1160       1.1  thorpej 		return (QOPERR_SYSCALL);
   1161       1.1  thorpej 	fltrinfo->handle = fltr_add.filter_handle;
   1162       1.1  thorpej 	return (0);
   1163       1.1  thorpej }
   1164       1.1  thorpej 
   1165       1.1  thorpej static int
   1166       1.1  thorpej hfsc_delete_filter(struct fltrinfo *fltrinfo)
   1167       1.1  thorpej {
   1168       1.1  thorpej 	struct hfsc_delete_filter fltr_del;
   1169       1.1  thorpej 
   1170       1.1  thorpej 	memset(&fltr_del, 0, sizeof(fltr_del));
   1171       1.1  thorpej 	strncpy(fltr_del.iface.hfsc_ifname, fltrinfo->clinfo->ifinfo->ifname,
   1172       1.1  thorpej 		IFNAMSIZ);
   1173       1.1  thorpej 	fltr_del.filter_handle = fltrinfo->handle;
   1174       1.1  thorpej 
   1175       1.1  thorpej 	if (ioctl(hfsc_fd, HFSC_DEL_FILTER, &fltr_del) < 0)
   1176       1.1  thorpej 		return (QOPERR_SYSCALL);
   1177       1.1  thorpej 	return (0);
   1178       1.1  thorpej }
   1179