Home | History | Annotate | Line # | Download | only in libaltq
qop_cdnr.c revision 1.2
      1  1.2   itojun /*	$KAME: qop_cdnr.c,v 1.7 2001/08/15 12:51:57 kjc Exp $	*/
      2  1.1  thorpej /*
      3  1.1  thorpej  * Copyright (C) 1999-2000
      4  1.1  thorpej  *	Sony Computer Science Laboratories, Inc.  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  * 1. Redistributions of source code must retain the above copyright
     10  1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     11  1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     14  1.1  thorpej  *
     15  1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
     16  1.1  thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  1.1  thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  1.1  thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
     19  1.1  thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  1.1  thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  1.1  thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  1.1  thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  1.1  thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  1.1  thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  1.1  thorpej  * SUCH DAMAGE.
     26  1.1  thorpej  */
     27  1.1  thorpej 
     28  1.1  thorpej #include <sys/param.h>
     29  1.1  thorpej #include <sys/socket.h>
     30  1.1  thorpej #include <sys/sockio.h>
     31  1.1  thorpej #include <sys/ioctl.h>
     32  1.1  thorpej #include <sys/fcntl.h>
     33  1.1  thorpej #include <net/if.h>
     34  1.1  thorpej #include <netinet/in.h>
     35  1.1  thorpej #include <arpa/inet.h>
     36  1.1  thorpej 
     37  1.1  thorpej #include <stdio.h>
     38  1.1  thorpej #include <stdlib.h>
     39  1.1  thorpej #include <unistd.h>
     40  1.1  thorpej #include <stddef.h>
     41  1.1  thorpej #include <string.h>
     42  1.1  thorpej #include <ctype.h>
     43  1.1  thorpej #include <errno.h>
     44  1.1  thorpej #include <syslog.h>
     45  1.1  thorpej #include <netdb.h>
     46  1.1  thorpej 
     47  1.1  thorpej #include <altq/altq.h>
     48  1.1  thorpej #include <altq/altq_cdnr.h>
     49  1.1  thorpej #include "altq_qop.h"
     50  1.1  thorpej #include "qop_cdnr.h"
     51  1.1  thorpej /*
     52  1.1  thorpej  * diffserve traffic conditioner support
     53  1.1  thorpej  *
     54  1.1  thorpej  * we use the existing qop interface to support conditioner.
     55  1.1  thorpej  */
     56  1.1  thorpej 
     57  1.2   itojun static struct ifinfo *cdnr_ifname2ifinfo(const char *);
     58  1.2   itojun static int cdnr_attach(struct ifinfo *);
     59  1.2   itojun static int cdnr_detach(struct ifinfo *);
     60  1.2   itojun static int cdnr_enable(struct ifinfo *);
     61  1.2   itojun static int cdnr_disable(struct ifinfo *);
     62  1.2   itojun static int cdnr_add_class(struct classinfo *);
     63  1.2   itojun static int cdnr_modify_class(struct classinfo *, void *);
     64  1.2   itojun static int cdnr_delete_class(struct classinfo *);
     65  1.2   itojun static int cdnr_add_filter(struct fltrinfo *);
     66  1.2   itojun static int cdnr_delete_filter(struct fltrinfo *);
     67  1.2   itojun static int verify_tbprofile(struct tb_profile *, const char *);
     68  1.1  thorpej 
     69  1.1  thorpej #define CDNR_DEVICE	"/dev/altq/cdnr"
     70  1.1  thorpej 
     71  1.1  thorpej static int cdnr_fd = -1;
     72  1.1  thorpej static int cdnr_refcount = 0;
     73  1.1  thorpej 
     74  1.1  thorpej static struct qdisc_ops cdnr_qdisc = {
     75  1.1  thorpej 	ALTQT_CDNR,
     76  1.1  thorpej 	"cdnr",
     77  1.1  thorpej 	cdnr_attach,
     78  1.1  thorpej 	cdnr_detach,
     79  1.1  thorpej 	NULL,			/* clear */
     80  1.1  thorpej 	cdnr_enable,
     81  1.1  thorpej 	cdnr_disable,
     82  1.1  thorpej 	cdnr_add_class,
     83  1.1  thorpej 	cdnr_modify_class,
     84  1.1  thorpej 	cdnr_delete_class,
     85  1.1  thorpej 	cdnr_add_filter,
     86  1.1  thorpej 	cdnr_delete_filter,
     87  1.1  thorpej };
     88  1.1  thorpej 
     89  1.1  thorpej u_long
     90  1.1  thorpej cdnr_name2handle(const char *ifname, const char *cdnr_name)
     91  1.1  thorpej {
     92  1.1  thorpej 	struct ifinfo		*ifinfo;
     93  1.1  thorpej 	struct classinfo	*clinfo;
     94  1.1  thorpej 
     95  1.1  thorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
     96  1.1  thorpej 		return (CDNR_NULL_HANDLE);
     97  1.1  thorpej 
     98  1.1  thorpej 	if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
     99  1.1  thorpej 		return (CDNR_NULL_HANDLE);
    100  1.1  thorpej 
    101  1.1  thorpej 	return (clinfo->handle);
    102  1.1  thorpej }
    103  1.1  thorpej 
    104  1.1  thorpej static struct ifinfo *
    105  1.1  thorpej cdnr_ifname2ifinfo(const char *ifname)
    106  1.1  thorpej {
    107  1.1  thorpej 	struct ifinfo	*ifinfo;
    108  1.1  thorpej 	char input_ifname[64];
    109  1.1  thorpej 
    110  1.1  thorpej 	/*
    111  1.1  thorpej 	 * search for an existing input interface
    112  1.1  thorpej 	 */
    113  1.1  thorpej 	if ((ifinfo = input_ifname2ifinfo(ifname)) != NULL)
    114  1.1  thorpej 		return (ifinfo);
    115  1.1  thorpej 
    116  1.1  thorpej 	/*
    117  1.1  thorpej 	 * if there is a corresponding output interface,
    118  1.1  thorpej 	 * create an input interface by prepending "_" to
    119  1.1  thorpej 	 * its name.
    120  1.1  thorpej 	 */
    121  1.1  thorpej 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
    122  1.1  thorpej 		return (NULL);
    123  1.1  thorpej 
    124  1.1  thorpej 	input_ifname[0] = '_';
    125  1.2   itojun 	strlcpy(input_ifname+1, ifname, sizeof(input_ifname)-1);
    126  1.1  thorpej 	if (qop_add_if(&ifinfo, input_ifname, 0, &cdnr_qdisc, NULL) != 0) {
    127  1.1  thorpej 		LOG(LOG_ERR, errno,
    128  1.1  thorpej 		    "cdnr_ifname2ifinfo: can't add a input interface %s\n",
    129  1.1  thorpej 		    ifname);
    130  1.1  thorpej 		return (NULL);
    131  1.1  thorpej 	}
    132  1.1  thorpej 	return (ifinfo);
    133  1.1  thorpej }
    134  1.1  thorpej 
    135  1.1  thorpej int
    136  1.1  thorpej qcmd_cdnr_add_element(struct tc_action *rp, const char *ifname,
    137  1.1  thorpej 		   const char *cdnr_name, struct tc_action *action)
    138  1.1  thorpej {
    139  1.1  thorpej 	struct ifinfo		*ifinfo;
    140  1.1  thorpej 	struct classinfo	*clinfo;
    141  1.1  thorpej 	int error;
    142  1.1  thorpej 
    143  1.1  thorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
    144  1.1  thorpej 		return (QOPERR_BADIF);
    145  1.1  thorpej 
    146  1.1  thorpej 	if ((error = qop_cdnr_add_element(&clinfo, cdnr_name, ifinfo,
    147  1.1  thorpej 					  action)) != 0) {
    148  1.1  thorpej 		LOG(LOG_ERR, errno, "%s: add element failed!\n",
    149  1.1  thorpej 		    qoperror(error));
    150  1.1  thorpej 		return (error);
    151  1.1  thorpej 	}
    152  1.1  thorpej 
    153  1.1  thorpej 	if (rp != NULL) {
    154  1.1  thorpej 		rp->tca_code = TCACODE_HANDLE;
    155  1.1  thorpej 		rp->tca_handle = clinfo->handle;
    156  1.1  thorpej 	}
    157  1.1  thorpej 	return (0);
    158  1.1  thorpej }
    159  1.1  thorpej 
    160  1.1  thorpej int
    161  1.1  thorpej qcmd_cdnr_add_tbmeter(struct tc_action *rp, const char *ifname,
    162  1.1  thorpej 		      const char *cdnr_name,
    163  1.1  thorpej 		      struct tb_profile *profile,
    164  1.1  thorpej 		      struct tc_action *in_action,
    165  1.1  thorpej 		      struct tc_action *out_action)
    166  1.1  thorpej {
    167  1.1  thorpej 	struct ifinfo		*ifinfo;
    168  1.1  thorpej 	struct classinfo	*clinfo;
    169  1.1  thorpej 	int error;
    170  1.1  thorpej 
    171  1.1  thorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
    172  1.1  thorpej 		return (QOPERR_BADIF);
    173  1.1  thorpej 
    174  1.1  thorpej 	verify_tbprofile(profile, cdnr_name);
    175  1.1  thorpej 
    176  1.1  thorpej 	if ((error = qop_cdnr_add_tbmeter(&clinfo, cdnr_name, ifinfo,
    177  1.1  thorpej 				  profile, in_action, out_action)) != 0) {
    178  1.1  thorpej 		LOG(LOG_ERR, errno, "%s: add tbmeter failed!\n",
    179  1.1  thorpej 		    qoperror(error));
    180  1.1  thorpej 		return (error);
    181  1.1  thorpej 	}
    182  1.1  thorpej 
    183  1.1  thorpej 	if (rp != NULL) {
    184  1.1  thorpej 		rp->tca_code = TCACODE_HANDLE;
    185  1.1  thorpej 		rp->tca_handle = clinfo->handle;
    186  1.1  thorpej 	}
    187  1.1  thorpej 	return (0);
    188  1.1  thorpej }
    189  1.1  thorpej 
    190  1.1  thorpej int
    191  1.1  thorpej qcmd_cdnr_add_trtcm(struct tc_action *rp, const char *ifname,
    192  1.1  thorpej 		    const char *cdnr_name,
    193  1.1  thorpej 		    struct tb_profile *cmtd_profile,
    194  1.1  thorpej 		    struct tb_profile *peak_profile,
    195  1.1  thorpej 		    struct tc_action *green_action,
    196  1.1  thorpej 		    struct tc_action *yellow_action,
    197  1.1  thorpej 		    struct tc_action *red_action, int coloraware)
    198  1.1  thorpej {
    199  1.1  thorpej 	struct ifinfo		*ifinfo;
    200  1.1  thorpej 	struct classinfo	*clinfo;
    201  1.1  thorpej 	int error;
    202  1.1  thorpej 
    203  1.1  thorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
    204  1.1  thorpej 		return (QOPERR_BADIF);
    205  1.1  thorpej 
    206  1.1  thorpej 	verify_tbprofile(cmtd_profile, cdnr_name);
    207  1.1  thorpej 	verify_tbprofile(peak_profile, cdnr_name);
    208  1.1  thorpej 
    209  1.1  thorpej 	if ((error = qop_cdnr_add_trtcm(&clinfo, cdnr_name, ifinfo,
    210  1.1  thorpej 			  cmtd_profile, peak_profile,
    211  1.1  thorpej 			  green_action, yellow_action, red_action,
    212  1.1  thorpej 	     		  coloraware)) != 0) {
    213  1.1  thorpej 		LOG(LOG_ERR, errno, "%s: add trtcm failed!\n",
    214  1.1  thorpej 		    qoperror(error));
    215  1.1  thorpej 		return (error);
    216  1.1  thorpej 	}
    217  1.1  thorpej 
    218  1.1  thorpej 	if (rp != NULL) {
    219  1.1  thorpej 		rp->tca_code = TCACODE_HANDLE;
    220  1.1  thorpej 		rp->tca_handle = clinfo->handle;
    221  1.1  thorpej 	}
    222  1.1  thorpej 	return (0);
    223  1.1  thorpej }
    224  1.1  thorpej 
    225  1.1  thorpej int
    226  1.1  thorpej qcmd_cdnr_add_tswtcm(struct tc_action *rp, const char *ifname,
    227  1.1  thorpej 		     const char *cdnr_name, const u_int32_t cmtd_rate,
    228  1.1  thorpej 		     const u_int32_t peak_rate, const u_int32_t avg_interval,
    229  1.1  thorpej 		     struct tc_action *green_action,
    230  1.1  thorpej 		     struct tc_action *yellow_action,
    231  1.1  thorpej 		     struct tc_action *red_action)
    232  1.1  thorpej {
    233  1.1  thorpej 	struct ifinfo		*ifinfo;
    234  1.1  thorpej 	struct classinfo	*clinfo;
    235  1.1  thorpej 	int error;
    236  1.1  thorpej 
    237  1.1  thorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
    238  1.1  thorpej 		return (QOPERR_BADIF);
    239  1.1  thorpej 
    240  1.1  thorpej 	if (cmtd_rate > peak_rate) {
    241  1.1  thorpej 		LOG(LOG_ERR, 0,
    242  1.1  thorpej 		    "add tswtcm: cmtd_rate larger than peak_rate!\n");
    243  1.1  thorpej 		return (QOPERR_INVAL);
    244  1.1  thorpej 	}
    245  1.1  thorpej 
    246  1.1  thorpej 	if ((error = qop_cdnr_add_tswtcm(&clinfo, cdnr_name, ifinfo,
    247  1.1  thorpej 					cmtd_rate, peak_rate, avg_interval,
    248  1.1  thorpej 					green_action, yellow_action,
    249  1.1  thorpej 					red_action)) != 0) {
    250  1.1  thorpej 		LOG(LOG_ERR, errno, "%s: add tswtcm failed!\n",
    251  1.1  thorpej 		    qoperror(error));
    252  1.1  thorpej 		return (error);
    253  1.1  thorpej 	}
    254  1.1  thorpej 
    255  1.1  thorpej 	if (rp != NULL) {
    256  1.1  thorpej 		rp->tca_code = TCACODE_HANDLE;
    257  1.1  thorpej 		rp->tca_handle = clinfo->handle;
    258  1.1  thorpej 	}
    259  1.1  thorpej 	return (0);
    260  1.1  thorpej }
    261  1.1  thorpej 
    262  1.1  thorpej int
    263  1.1  thorpej qcmd_cdnr_delete(const char *ifname, const char *cdnr_name)
    264  1.1  thorpej {
    265  1.1  thorpej 	struct ifinfo		*ifinfo;
    266  1.1  thorpej 	struct classinfo	*clinfo;
    267  1.1  thorpej 
    268  1.1  thorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
    269  1.1  thorpej 		return (QOPERR_BADIF);
    270  1.1  thorpej 
    271  1.1  thorpej 	if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
    272  1.1  thorpej 		return (QOPERR_BADCLASS);
    273  1.1  thorpej 
    274  1.1  thorpej 	return qop_delete_cdnr(clinfo);
    275  1.1  thorpej }
    276  1.1  thorpej 
    277  1.1  thorpej /*
    278  1.1  thorpej  * class operations:
    279  1.1  thorpej  *	class structure is used to hold conditioners.
    280  1.1  thorpej  *	XXX
    281  1.1  thorpej  *	conditioners has dependencies in the reverse order; parent nodes
    282  1.1  thorpej  *	refere to child nodes, and thus, a child is created first and
    283  1.1  thorpej  *	parents should be removed first.
    284  1.1  thorpej  *	qop_add_cdnr() and qop_delete_cdnr() are wrapper functions
    285  1.1  thorpej  *	of qop_add_class() and qop_delete_class(), and takes care
    286  1.1  thorpej  *	of dependencies.
    287  1.1  thorpej  *	1. when adding a conditioner, it is created as a child of a
    288  1.1  thorpej  *	   dummy root class.  then, the child conditioners are made
    289  1.1  thorpej  *	   as its children.
    290  1.1  thorpej  *	2. when deleting a conditioner, its child conditioners are made
    291  1.1  thorpej  *	   as children of the dummy root class.  then, the conditioner
    292  1.1  thorpej  *	   is deleted.
    293  1.1  thorpej  */
    294  1.1  thorpej 
    295  1.1  thorpej int
    296  1.1  thorpej qop_add_cdnr(struct classinfo **rp, const char *cdnr_name,
    297  1.1  thorpej 	     struct ifinfo *ifinfo, struct classinfo **childlist,
    298  1.1  thorpej 	     void *cdnr_private)
    299  1.1  thorpej {
    300  1.1  thorpej 	struct classinfo	*clinfo, *root, *cl, *prev;
    301  1.1  thorpej 	int error;
    302  1.1  thorpej 
    303  1.1  thorpej 	/*
    304  1.1  thorpej 	 * if there is no root cdnr, create one.
    305  1.1  thorpej 	 */
    306  1.1  thorpej 	if ((root = get_rootclass(ifinfo)) == NULL) {
    307  1.1  thorpej 		if ((error = qop_add_class(&root, "cdnr_root",
    308  1.1  thorpej 					   ifinfo, NULL, NULL)) != 0) {
    309  1.1  thorpej 			LOG(LOG_ERR, errno,
    310  1.1  thorpej 			    "cdnr: %s: can't create dummy root cdnr on %s!\n",
    311  1.1  thorpej 			    qoperror(error), ifinfo->ifname);
    312  1.1  thorpej 			return (QOPERR_CLASS);
    313  1.1  thorpej 		}
    314  1.1  thorpej 	}
    315  1.1  thorpej 
    316  1.1  thorpej 	/*
    317  1.1  thorpej 	 * create a class as a child of a root class.
    318  1.1  thorpej 	 */
    319  1.1  thorpej 	if ((error = qop_add_class(&clinfo, cdnr_name,
    320  1.1  thorpej 				   ifinfo, root, cdnr_private)) != 0)
    321  1.1  thorpej 		return (error);
    322  1.1  thorpej 	/*
    323  1.1  thorpej 	 * move child nodes
    324  1.1  thorpej 	 */
    325  1.1  thorpej 	for (cl = *childlist; cl != NULL; cl = *++childlist) {
    326  1.1  thorpej 		if (cl->parent != root) {
    327  1.1  thorpej 			/*
    328  1.1  thorpej 			 * this conditioner already has a non-root parent.
    329  1.1  thorpej 			 * we can't track down a multi-parent node by a
    330  1.1  thorpej 			 * tree structure; leave it as it is.
    331  1.1  thorpej 			 * (we need a mechanism similar to a symbolic link
    332  1.1  thorpej 			 * in a file system)
    333  1.1  thorpej 			 */
    334  1.1  thorpej 			continue;
    335  1.1  thorpej 		}
    336  1.1  thorpej 		/* remove this child from the root */
    337  1.1  thorpej 		if (root->child == cl)
    338  1.1  thorpej 			root->child = cl->sibling;
    339  1.1  thorpej 		else for (prev = root->child;
    340  1.1  thorpej 			  prev->sibling != NULL; prev = prev->sibling)
    341  1.1  thorpej 			if (prev->sibling == cl) {
    342  1.1  thorpej 				prev->sibling = cl->sibling;
    343  1.1  thorpej 				break;
    344  1.1  thorpej 			}
    345  1.1  thorpej 
    346  1.1  thorpej 		/* add as a child */
    347  1.1  thorpej 		cl->sibling = clinfo->child;
    348  1.1  thorpej 		clinfo->child = cl;
    349  1.1  thorpej 		cl->parent = clinfo;
    350  1.1  thorpej 	}
    351  1.1  thorpej 
    352  1.1  thorpej 	if (rp != NULL)
    353  1.1  thorpej 		*rp = clinfo;
    354  1.1  thorpej 	return (0);
    355  1.1  thorpej }
    356  1.1  thorpej 
    357  1.1  thorpej int
    358  1.1  thorpej qop_delete_cdnr(struct classinfo *clinfo)
    359  1.1  thorpej {
    360  1.1  thorpej 	struct classinfo *cl, *root;
    361  1.1  thorpej 	int error;
    362  1.1  thorpej 
    363  1.1  thorpej 	if ((root = get_rootclass(clinfo->ifinfo)) == NULL) {
    364  1.1  thorpej 		LOG(LOG_ERR, 0, "qop_delete_cdnr: no root cdnr!\n");
    365  1.1  thorpej 		return (QOPERR_CLASS);
    366  1.1  thorpej 	}
    367  1.1  thorpej 
    368  1.1  thorpej 	if (clinfo->parent != root)
    369  1.1  thorpej 		return (QOPERR_CLASS_PERM);
    370  1.1  thorpej 
    371  1.1  thorpej 	if ((cl = clinfo->child) != NULL) {
    372  1.1  thorpej 		/* change child's parent to root, find the last child */
    373  1.1  thorpej 		while (cl->sibling != NULL) {
    374  1.1  thorpej 			cl->parent = root;
    375  1.1  thorpej 			cl = cl->sibling;
    376  1.1  thorpej 		}
    377  1.1  thorpej 		cl->parent = root;
    378  1.1  thorpej 
    379  1.1  thorpej 		/* move children to siblings */
    380  1.1  thorpej 		cl->sibling = clinfo->sibling;
    381  1.1  thorpej 		clinfo->sibling = cl;
    382  1.1  thorpej 		clinfo->child = NULL;
    383  1.1  thorpej 	}
    384  1.1  thorpej 
    385  1.1  thorpej 	error = qop_delete_class(clinfo);
    386  1.1  thorpej 
    387  1.1  thorpej 	if (error) {
    388  1.1  thorpej 		/* ick! restore the class tree */
    389  1.1  thorpej 		if (cl != NULL) {
    390  1.1  thorpej 			clinfo->child = clinfo->sibling;
    391  1.1  thorpej 			clinfo->sibling = cl->sibling;
    392  1.1  thorpej 			cl->sibling = NULL;
    393  1.1  thorpej 			/* restore parent field */
    394  1.1  thorpej 			for (cl = clinfo->child; cl != NULL; cl = cl->sibling)
    395  1.1  thorpej 				cl->parent = clinfo;
    396  1.1  thorpej 		}
    397  1.1  thorpej 	}
    398  1.1  thorpej 	return (error);
    399  1.1  thorpej }
    400  1.1  thorpej 
    401  1.1  thorpej int
    402  1.1  thorpej qop_cdnr_add_element(struct classinfo **rp, const char *cdnr_name,
    403  1.1  thorpej 		     struct ifinfo *ifinfo, struct tc_action *action)
    404  1.1  thorpej {
    405  1.1  thorpej 	struct classinfo *clinfo, *clist[2];
    406  1.1  thorpej 	struct cdnrinfo *cdnrinfo = NULL;
    407  1.1  thorpej 	int error;
    408  1.1  thorpej 
    409  1.1  thorpej 	if (action->tca_code == TCACODE_HANDLE) {
    410  1.1  thorpej 		clinfo = clhandle2clinfo(ifinfo, action->tca_handle);
    411  1.1  thorpej 		if (clinfo == NULL)
    412  1.1  thorpej 			return (QOPERR_BADCLASS);
    413  1.1  thorpej 		clist[0] = clinfo;
    414  1.1  thorpej 		clist[1] = NULL;
    415  1.1  thorpej #if 1
    416  1.1  thorpej 		/*
    417  1.1  thorpej 		 * if the conditioner referred to doesn't have a name,
    418  1.1  thorpej 		 * this is called just to add a name to it.
    419  1.1  thorpej 		 * we can simply add the name to the existing conditioner
    420  1.1  thorpej 		 * and return it.
    421  1.1  thorpej 		 */
    422  1.1  thorpej 		if (cdnr_name != NULL &&
    423  1.1  thorpej 		    strcmp(clinfo->clname, "(null)") == 0) {
    424  1.1  thorpej 			free(clinfo->clname);
    425  1.1  thorpej 			clinfo->clname = strdup(cdnr_name);
    426  1.1  thorpej 			if (rp != NULL)
    427  1.1  thorpej 				*rp = clinfo;
    428  1.1  thorpej 			return (0);
    429  1.1  thorpej 		}
    430  1.1  thorpej #endif
    431  1.1  thorpej 	} else
    432  1.1  thorpej 		clist[0] = NULL;
    433  1.1  thorpej 
    434  1.1  thorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
    435  1.1  thorpej 		return (QOPERR_NOMEM);
    436  1.1  thorpej 
    437  1.1  thorpej 	cdnrinfo->tce_type = TCETYPE_ELEMENT;
    438  1.1  thorpej 	cdnrinfo->tce_un.element.action = *action;
    439  1.1  thorpej 
    440  1.1  thorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
    441  1.1  thorpej 				  cdnrinfo)) != 0)
    442  1.1  thorpej 		goto err_ret;
    443  1.1  thorpej 
    444  1.1  thorpej 	if (rp != NULL)
    445  1.1  thorpej 		*rp = clinfo;
    446  1.1  thorpej 	return (0);
    447  1.1  thorpej 
    448  1.1  thorpej  err_ret:
    449  1.1  thorpej 	if (cdnrinfo != NULL)
    450  1.1  thorpej 		free(cdnrinfo);
    451  1.1  thorpej 	return (error);
    452  1.1  thorpej }
    453  1.1  thorpej 
    454  1.1  thorpej int
    455  1.1  thorpej qop_cdnr_add_tbmeter(struct classinfo **rp, const char *cdnr_name,
    456  1.1  thorpej 		     struct ifinfo *ifinfo,
    457  1.1  thorpej 		     struct tb_profile *profile,
    458  1.1  thorpej 		     struct tc_action *in_action,
    459  1.1  thorpej 		     struct tc_action *out_action)
    460  1.1  thorpej {
    461  1.1  thorpej 	struct classinfo *clinfo, *clist[3];
    462  1.1  thorpej 	struct cdnrinfo *cdnrinfo = NULL;
    463  1.1  thorpej 	int n, error;
    464  1.1  thorpej 
    465  1.1  thorpej 	n = 0;
    466  1.1  thorpej 	if (in_action->tca_code == TCACODE_HANDLE) {
    467  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, in_action->tca_handle);
    468  1.1  thorpej 		if (clist[n] == NULL)
    469  1.1  thorpej 			return (QOPERR_BADCLASS);
    470  1.1  thorpej 		n++;
    471  1.1  thorpej 	}
    472  1.1  thorpej 	if (out_action->tca_code == TCACODE_HANDLE) {
    473  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, out_action->tca_handle);
    474  1.1  thorpej 		if (clist[n] == NULL)
    475  1.1  thorpej 			return (QOPERR_BADCLASS);
    476  1.1  thorpej 		n++;
    477  1.1  thorpej 	}
    478  1.1  thorpej 	clist[n] = NULL;
    479  1.1  thorpej 
    480  1.1  thorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
    481  1.1  thorpej 		return (QOPERR_NOMEM);
    482  1.1  thorpej 
    483  1.1  thorpej 	cdnrinfo->tce_type = TCETYPE_TBMETER;
    484  1.1  thorpej 	cdnrinfo->tce_un.tbmeter.profile = *profile;
    485  1.1  thorpej 	cdnrinfo->tce_un.tbmeter.in_action = *in_action;
    486  1.1  thorpej 	cdnrinfo->tce_un.tbmeter.out_action = *out_action;
    487  1.1  thorpej 
    488  1.1  thorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
    489  1.1  thorpej 				   cdnrinfo)) != 0)
    490  1.1  thorpej 		goto err_ret;
    491  1.1  thorpej 
    492  1.1  thorpej 	if (rp != NULL)
    493  1.1  thorpej 		*rp = clinfo;
    494  1.1  thorpej 	return (0);
    495  1.1  thorpej 
    496  1.1  thorpej  err_ret:
    497  1.1  thorpej 	if (cdnrinfo != NULL)
    498  1.1  thorpej 		free(cdnrinfo);
    499  1.1  thorpej 	return (error);
    500  1.1  thorpej }
    501  1.1  thorpej 
    502  1.1  thorpej int
    503  1.1  thorpej qop_cdnr_modify_tbmeter(struct classinfo *clinfo, struct tb_profile *profile)
    504  1.1  thorpej {
    505  1.1  thorpej 	struct cdnrinfo *cdnrinfo = clinfo->private;
    506  1.1  thorpej 
    507  1.1  thorpej 	if (cdnrinfo->tce_type != TCETYPE_TBMETER)
    508  1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    509  1.1  thorpej 	cdnrinfo->tce_un.tbmeter.profile = *profile;
    510  1.1  thorpej 
    511  1.1  thorpej 	return qop_modify_class(clinfo, NULL);
    512  1.1  thorpej }
    513  1.1  thorpej 
    514  1.1  thorpej int
    515  1.1  thorpej qop_cdnr_add_trtcm(struct classinfo **rp, const char *cdnr_name,
    516  1.1  thorpej 		   struct ifinfo *ifinfo,
    517  1.1  thorpej 		   struct tb_profile *cmtd_profile,
    518  1.1  thorpej 		   struct tb_profile *peak_profile,
    519  1.1  thorpej 		   struct tc_action *green_action,
    520  1.1  thorpej 		   struct tc_action *yellow_action,
    521  1.1  thorpej 		   struct tc_action *red_action, int coloraware)
    522  1.1  thorpej {
    523  1.1  thorpej 	struct classinfo *clinfo, *clist[4];
    524  1.1  thorpej 	struct cdnrinfo *cdnrinfo = NULL;
    525  1.1  thorpej 	int n, error;
    526  1.1  thorpej 
    527  1.1  thorpej 	n = 0;
    528  1.1  thorpej 	if (green_action->tca_code == TCACODE_HANDLE) {
    529  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
    530  1.1  thorpej 		if (clist[n] == NULL)
    531  1.1  thorpej 			return (QOPERR_BADCLASS);
    532  1.1  thorpej 		n++;
    533  1.1  thorpej 	}
    534  1.1  thorpej 	if (yellow_action->tca_code == TCACODE_HANDLE) {
    535  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
    536  1.1  thorpej 		if (clist[n] == NULL)
    537  1.1  thorpej 			return (QOPERR_BADCLASS);
    538  1.1  thorpej 		n++;
    539  1.1  thorpej 	}
    540  1.1  thorpej 	if (red_action->tca_code == TCACODE_HANDLE) {
    541  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
    542  1.1  thorpej 		if (clist[n] == NULL)
    543  1.1  thorpej 			return (QOPERR_BADCLASS);
    544  1.1  thorpej 		n++;
    545  1.1  thorpej 	}
    546  1.1  thorpej 	clist[n] = NULL;
    547  1.1  thorpej 
    548  1.1  thorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
    549  1.1  thorpej 		return (QOPERR_NOMEM);
    550  1.1  thorpej 
    551  1.1  thorpej 	cdnrinfo->tce_type = TCETYPE_TRTCM;
    552  1.1  thorpej 	cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
    553  1.1  thorpej 	cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
    554  1.1  thorpej 	cdnrinfo->tce_un.trtcm.green_action = *green_action;
    555  1.1  thorpej 	cdnrinfo->tce_un.trtcm.yellow_action = *yellow_action;
    556  1.1  thorpej 	cdnrinfo->tce_un.trtcm.red_action = *red_action;
    557  1.1  thorpej 	cdnrinfo->tce_un.trtcm.coloraware = coloraware;
    558  1.1  thorpej 
    559  1.1  thorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
    560  1.1  thorpej 				  cdnrinfo)) != 0)
    561  1.1  thorpej 		goto err_ret;
    562  1.1  thorpej 
    563  1.1  thorpej 	if (rp != NULL)
    564  1.1  thorpej 		*rp = clinfo;
    565  1.1  thorpej 	return (0);
    566  1.1  thorpej 
    567  1.1  thorpej  err_ret:
    568  1.1  thorpej 	if (cdnrinfo != NULL)
    569  1.1  thorpej 		free(cdnrinfo);
    570  1.1  thorpej 	return (error);
    571  1.1  thorpej }
    572  1.1  thorpej 
    573  1.1  thorpej int
    574  1.1  thorpej qop_cdnr_modify_trtcm(struct classinfo *clinfo,
    575  1.1  thorpej 		      struct tb_profile *cmtd_profile,
    576  1.1  thorpej 		      struct tb_profile *peak_profile, int coloraware)
    577  1.1  thorpej {
    578  1.1  thorpej 	struct cdnrinfo *cdnrinfo = clinfo->private;
    579  1.1  thorpej 
    580  1.1  thorpej 	if (cdnrinfo->tce_type != TCETYPE_TRTCM)
    581  1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    582  1.1  thorpej 	cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
    583  1.1  thorpej 	cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
    584  1.1  thorpej 	cdnrinfo->tce_un.trtcm.coloraware = coloraware;
    585  1.1  thorpej 
    586  1.1  thorpej 	return qop_modify_class(clinfo, NULL);
    587  1.1  thorpej }
    588  1.1  thorpej 
    589  1.1  thorpej int
    590  1.1  thorpej qop_cdnr_add_tswtcm(struct classinfo **rp, const char *cdnr_name,
    591  1.1  thorpej 		    struct ifinfo *ifinfo, const u_int32_t cmtd_rate,
    592  1.1  thorpej 		    const u_int32_t peak_rate, const u_int32_t avg_interval,
    593  1.1  thorpej 		    struct tc_action *green_action,
    594  1.1  thorpej 		    struct tc_action *yellow_action,
    595  1.1  thorpej 		    struct tc_action *red_action)
    596  1.1  thorpej {
    597  1.1  thorpej 	struct classinfo *clinfo, *clist[4];
    598  1.1  thorpej 	struct cdnrinfo *cdnrinfo = NULL;
    599  1.1  thorpej 	int n, error;
    600  1.1  thorpej 
    601  1.1  thorpej 	n = 0;
    602  1.1  thorpej 	if (green_action->tca_code == TCACODE_HANDLE) {
    603  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
    604  1.1  thorpej 		if (clist[n] == NULL)
    605  1.1  thorpej 			return (QOPERR_BADCLASS);
    606  1.1  thorpej 		n++;
    607  1.1  thorpej 	}
    608  1.1  thorpej 	if (yellow_action->tca_code == TCACODE_HANDLE) {
    609  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
    610  1.1  thorpej 		if (clist[n] == NULL)
    611  1.1  thorpej 			return (QOPERR_BADCLASS);
    612  1.1  thorpej 		n++;
    613  1.1  thorpej 	}
    614  1.1  thorpej 	if (red_action->tca_code == TCACODE_HANDLE) {
    615  1.1  thorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
    616  1.1  thorpej 		if (clist[n] == NULL)
    617  1.1  thorpej 			return (QOPERR_BADCLASS);
    618  1.1  thorpej 		n++;
    619  1.1  thorpej 	}
    620  1.1  thorpej 	clist[n] = NULL;
    621  1.1  thorpej 
    622  1.1  thorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
    623  1.1  thorpej 		return (QOPERR_NOMEM);
    624  1.1  thorpej 
    625  1.1  thorpej 	cdnrinfo->tce_type = TCETYPE_TSWTCM;
    626  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
    627  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
    628  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
    629  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.green_action = *green_action;
    630  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.yellow_action = *yellow_action;
    631  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.red_action = *red_action;
    632  1.1  thorpej 
    633  1.1  thorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
    634  1.1  thorpej 				  cdnrinfo)) != 0)
    635  1.1  thorpej 		goto err_ret;
    636  1.1  thorpej 
    637  1.1  thorpej 	if (rp != NULL)
    638  1.1  thorpej 		*rp = clinfo;
    639  1.1  thorpej 	return (0);
    640  1.1  thorpej 
    641  1.1  thorpej  err_ret:
    642  1.1  thorpej 	if (cdnrinfo != NULL)
    643  1.1  thorpej 		free(cdnrinfo);
    644  1.1  thorpej 	return (error);
    645  1.1  thorpej }
    646  1.1  thorpej 
    647  1.1  thorpej int
    648  1.1  thorpej qop_cdnr_modify_tswtcm(struct classinfo *clinfo, const u_int32_t cmtd_rate,
    649  1.1  thorpej 		       const u_int32_t peak_rate, const u_int32_t avg_interval)
    650  1.1  thorpej {
    651  1.1  thorpej 	struct cdnrinfo *cdnrinfo = clinfo->private;
    652  1.1  thorpej 
    653  1.1  thorpej 	if (cdnrinfo->tce_type != TCETYPE_TSWTCM)
    654  1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    655  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
    656  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
    657  1.1  thorpej 	cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
    658  1.1  thorpej 
    659  1.1  thorpej 	return qop_modify_class(clinfo, NULL);
    660  1.1  thorpej }
    661  1.1  thorpej 
    662  1.1  thorpej /*
    663  1.1  thorpej  *  system call interfaces for qdisc_ops
    664  1.1  thorpej  */
    665  1.1  thorpej static int
    666  1.1  thorpej cdnr_attach(struct ifinfo *ifinfo)
    667  1.1  thorpej {
    668  1.1  thorpej 	struct cdnr_interface iface;
    669  1.1  thorpej 
    670  1.1  thorpej 	if (cdnr_fd < 0 &&
    671  1.1  thorpej 	    (cdnr_fd = open(CDNR_DEVICE, O_RDWR)) < 0 &&
    672  1.1  thorpej 	    (cdnr_fd = open_module(CDNR_DEVICE, O_RDWR)) < 0) {
    673  1.1  thorpej 		LOG(LOG_ERR, errno, "CDNR open\n");
    674  1.1  thorpej 		return (QOPERR_SYSCALL);
    675  1.1  thorpej 	}
    676  1.1  thorpej 
    677  1.1  thorpej 	cdnr_refcount++;
    678  1.1  thorpej 	memset(&iface, 0, sizeof(iface));
    679  1.1  thorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
    680  1.1  thorpej 
    681  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_IF_ATTACH, &iface) < 0)
    682  1.1  thorpej 		return (QOPERR_SYSCALL);
    683  1.1  thorpej #if 1
    684  1.1  thorpej 	LOG(LOG_INFO, 0, "conditioner attached to %s\n", iface.cdnr_ifname);
    685  1.1  thorpej #endif
    686  1.1  thorpej 	return (0);
    687  1.1  thorpej }
    688  1.1  thorpej 
    689  1.1  thorpej static int
    690  1.1  thorpej cdnr_detach(struct ifinfo *ifinfo)
    691  1.1  thorpej {
    692  1.1  thorpej 	struct cdnr_interface iface;
    693  1.1  thorpej 
    694  1.1  thorpej 	memset(&iface, 0, sizeof(iface));
    695  1.1  thorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
    696  1.1  thorpej 
    697  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_IF_DETACH, &iface) < 0)
    698  1.1  thorpej 		return (QOPERR_SYSCALL);
    699  1.1  thorpej 
    700  1.1  thorpej 	if (--cdnr_refcount == 0) {
    701  1.1  thorpej 		close(cdnr_fd);
    702  1.1  thorpej 		cdnr_fd = -1;
    703  1.1  thorpej 	}
    704  1.1  thorpej 	return (0);
    705  1.1  thorpej }
    706  1.1  thorpej 
    707  1.1  thorpej static int
    708  1.1  thorpej cdnr_enable(struct ifinfo *ifinfo)
    709  1.1  thorpej {
    710  1.1  thorpej 	struct cdnr_interface iface;
    711  1.1  thorpej 
    712  1.1  thorpej 	memset(&iface, 0, sizeof(iface));
    713  1.1  thorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
    714  1.1  thorpej 
    715  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_ENABLE, &iface) < 0)
    716  1.1  thorpej 		return (QOPERR_SYSCALL);
    717  1.1  thorpej 	return (0);
    718  1.1  thorpej }
    719  1.1  thorpej 
    720  1.1  thorpej static int
    721  1.1  thorpej cdnr_disable(struct ifinfo *ifinfo)
    722  1.1  thorpej {
    723  1.1  thorpej 	struct cdnr_interface iface;
    724  1.1  thorpej 
    725  1.1  thorpej 	memset(&iface, 0, sizeof(iface));
    726  1.1  thorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
    727  1.1  thorpej 
    728  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_DISABLE, &iface) < 0)
    729  1.1  thorpej 		return (QOPERR_SYSCALL);
    730  1.1  thorpej 	return (0);
    731  1.1  thorpej }
    732  1.1  thorpej 
    733  1.1  thorpej static int
    734  1.1  thorpej cdnr_add_class(struct classinfo *clinfo)
    735  1.1  thorpej {
    736  1.1  thorpej 	struct cdnr_add_element element_add;
    737  1.1  thorpej 	struct cdnr_add_tbmeter tbmeter_add;
    738  1.1  thorpej 	struct cdnr_add_trtcm   trtcm_add;
    739  1.1  thorpej 	struct cdnr_add_tswtcm  tswtcm_add;
    740  1.1  thorpej 	struct cdnrinfo *cdnrinfo;
    741  1.1  thorpej 
    742  1.1  thorpej 	cdnrinfo = clinfo->private;
    743  1.1  thorpej 
    744  1.1  thorpej 	/* root class is a dummy class */
    745  1.1  thorpej 	if (clinfo->parent == NULL) {
    746  1.1  thorpej 		clinfo->handle = 0;
    747  1.1  thorpej 		return (0);
    748  1.1  thorpej 	}
    749  1.1  thorpej 
    750  1.1  thorpej 	switch (cdnrinfo->tce_type) {
    751  1.1  thorpej 	case TCETYPE_ELEMENT:
    752  1.1  thorpej 		memset(&element_add, 0, sizeof(element_add));
    753  1.1  thorpej 		strncpy(element_add.iface.cdnr_ifname,
    754  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    755  1.1  thorpej 		element_add.action = cdnrinfo->tce_un.element.action;
    756  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_ADD_ELEM, &element_add) < 0) {
    757  1.1  thorpej 			clinfo->handle = CDNR_NULL_HANDLE;
    758  1.1  thorpej 			return (QOPERR_SYSCALL);
    759  1.1  thorpej 		}
    760  1.1  thorpej 		clinfo->handle = element_add.cdnr_handle;
    761  1.1  thorpej 		break;
    762  1.1  thorpej 
    763  1.1  thorpej 	case TCETYPE_TBMETER:
    764  1.1  thorpej 		memset(&tbmeter_add, 0, sizeof(tbmeter_add));
    765  1.1  thorpej 		strncpy(tbmeter_add.iface.cdnr_ifname,
    766  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    767  1.1  thorpej 		tbmeter_add.profile = cdnrinfo->tce_un.tbmeter.profile;
    768  1.1  thorpej 		tbmeter_add.in_action = cdnrinfo->tce_un.tbmeter.in_action;
    769  1.1  thorpej 		tbmeter_add.out_action = cdnrinfo->tce_un.tbmeter.out_action;
    770  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_ADD_TBM, &tbmeter_add) < 0) {
    771  1.1  thorpej 			clinfo->handle = CDNR_NULL_HANDLE;
    772  1.1  thorpej 			return (QOPERR_SYSCALL);
    773  1.1  thorpej 		}
    774  1.1  thorpej 		clinfo->handle = tbmeter_add.cdnr_handle;
    775  1.1  thorpej 		break;
    776  1.1  thorpej 
    777  1.1  thorpej 	case TCETYPE_TRTCM:
    778  1.1  thorpej 		memset(&trtcm_add, 0, sizeof(trtcm_add));
    779  1.1  thorpej 		strncpy(trtcm_add.iface.cdnr_ifname,
    780  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    781  1.1  thorpej 		trtcm_add.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile;
    782  1.1  thorpej 		trtcm_add.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile;
    783  1.1  thorpej 		trtcm_add.green_action = cdnrinfo->tce_un.trtcm.green_action;
    784  1.1  thorpej 		trtcm_add.yellow_action = cdnrinfo->tce_un.trtcm.yellow_action;
    785  1.1  thorpej 		trtcm_add.red_action = cdnrinfo->tce_un.trtcm.red_action;
    786  1.1  thorpej 		trtcm_add.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
    787  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_ADD_TCM, &trtcm_add) < 0) {
    788  1.1  thorpej 			clinfo->handle = CDNR_NULL_HANDLE;
    789  1.1  thorpej 			return (QOPERR_SYSCALL);
    790  1.1  thorpej 		}
    791  1.1  thorpej 		clinfo->handle = trtcm_add.cdnr_handle;
    792  1.1  thorpej 		break;
    793  1.1  thorpej 
    794  1.1  thorpej 	case TCETYPE_TSWTCM:
    795  1.1  thorpej 		memset(&tswtcm_add, 0, sizeof(tswtcm_add));
    796  1.1  thorpej 		strncpy(tswtcm_add.iface.cdnr_ifname,
    797  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    798  1.1  thorpej 		tswtcm_add.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
    799  1.1  thorpej 		tswtcm_add.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
    800  1.1  thorpej 		tswtcm_add.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
    801  1.1  thorpej 		tswtcm_add.green_action = cdnrinfo->tce_un.tswtcm.green_action;
    802  1.1  thorpej 		tswtcm_add.yellow_action = cdnrinfo->tce_un.tswtcm.yellow_action;
    803  1.1  thorpej 		tswtcm_add.red_action = cdnrinfo->tce_un.tswtcm.red_action;
    804  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_ADD_TSW, &tswtcm_add) < 0) {
    805  1.1  thorpej 			clinfo->handle = CDNR_NULL_HANDLE;
    806  1.1  thorpej 			return (QOPERR_SYSCALL);
    807  1.1  thorpej 		}
    808  1.1  thorpej 		clinfo->handle = tswtcm_add.cdnr_handle;
    809  1.1  thorpej 		break;
    810  1.1  thorpej 
    811  1.1  thorpej 	default:
    812  1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    813  1.1  thorpej 	}
    814  1.1  thorpej 	return (0);
    815  1.1  thorpej }
    816  1.1  thorpej 
    817  1.1  thorpej static int
    818  1.1  thorpej cdnr_modify_class(struct classinfo *clinfo, void *arg)
    819  1.1  thorpej {
    820  1.1  thorpej 	struct cdnr_modify_tbmeter tbmeter_modify;
    821  1.1  thorpej 	struct cdnr_modify_trtcm   trtcm_modify;
    822  1.1  thorpej 	struct cdnr_modify_tswtcm  tswtcm_modify;
    823  1.1  thorpej 	struct cdnrinfo *cdnrinfo;
    824  1.1  thorpej 
    825  1.1  thorpej 	cdnrinfo = clinfo->private;
    826  1.1  thorpej 
    827  1.1  thorpej 	switch (cdnrinfo->tce_type) {
    828  1.1  thorpej 	case TCETYPE_TBMETER:
    829  1.1  thorpej 		memset(&tbmeter_modify, 0, sizeof(tbmeter_modify));
    830  1.1  thorpej 		strncpy(tbmeter_modify.iface.cdnr_ifname,
    831  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    832  1.1  thorpej 		tbmeter_modify.cdnr_handle = clinfo->handle;
    833  1.1  thorpej 		tbmeter_modify.profile = cdnrinfo->tce_un.tbmeter.profile;
    834  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_MOD_TBM, &tbmeter_modify) < 0)
    835  1.1  thorpej 			return (QOPERR_SYSCALL);
    836  1.1  thorpej 		break;
    837  1.1  thorpej 
    838  1.1  thorpej 	case TCETYPE_TRTCM:
    839  1.1  thorpej 		memset(&trtcm_modify, 0, sizeof(trtcm_modify));
    840  1.1  thorpej 		strncpy(trtcm_modify.iface.cdnr_ifname,
    841  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    842  1.1  thorpej 		trtcm_modify.cdnr_handle = clinfo->handle;
    843  1.1  thorpej 		trtcm_modify.cmtd_profile =
    844  1.1  thorpej 			cdnrinfo->tce_un.trtcm.cmtd_profile;
    845  1.1  thorpej 		trtcm_modify.peak_profile =
    846  1.1  thorpej 			cdnrinfo->tce_un.trtcm.peak_profile;
    847  1.1  thorpej 		trtcm_modify.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
    848  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_MOD_TCM, &trtcm_modify) < 0)
    849  1.1  thorpej 			return (QOPERR_SYSCALL);
    850  1.1  thorpej 		break;
    851  1.1  thorpej 
    852  1.1  thorpej 	case TCETYPE_TSWTCM:
    853  1.1  thorpej 		memset(&tswtcm_modify, 0, sizeof(tswtcm_modify));
    854  1.1  thorpej 		strncpy(tswtcm_modify.iface.cdnr_ifname,
    855  1.1  thorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
    856  1.1  thorpej 		tswtcm_modify.cdnr_handle = clinfo->handle;
    857  1.1  thorpej 		tswtcm_modify.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
    858  1.1  thorpej 		tswtcm_modify.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
    859  1.1  thorpej 		tswtcm_modify.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
    860  1.1  thorpej 		if (ioctl(cdnr_fd, CDNR_MOD_TSW, &tswtcm_modify) < 0)
    861  1.1  thorpej 			return (QOPERR_SYSCALL);
    862  1.1  thorpej 		break;
    863  1.1  thorpej 
    864  1.1  thorpej 	default:
    865  1.1  thorpej 		return (QOPERR_CLASS_INVAL);
    866  1.1  thorpej 	}
    867  1.1  thorpej 	return (0);
    868  1.1  thorpej }
    869  1.1  thorpej 
    870  1.1  thorpej static int
    871  1.1  thorpej cdnr_delete_class(struct classinfo *clinfo)
    872  1.1  thorpej {
    873  1.1  thorpej 	struct cdnr_delete_element element_delete;
    874  1.1  thorpej 
    875  1.1  thorpej 	if (clinfo->handle == CDNR_NULL_HANDLE)
    876  1.1  thorpej 		return (0);
    877  1.1  thorpej 
    878  1.1  thorpej 	memset(&element_delete, 0, sizeof(element_delete));
    879  1.1  thorpej 	strncpy(element_delete.iface.cdnr_ifname, clinfo->ifinfo->ifname+1,
    880  1.1  thorpej 		IFNAMSIZ);
    881  1.1  thorpej 	element_delete.cdnr_handle = clinfo->handle;
    882  1.1  thorpej 
    883  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_DEL_ELEM, &element_delete) < 0)
    884  1.1  thorpej 		return (QOPERR_SYSCALL);
    885  1.1  thorpej 	return (0);
    886  1.1  thorpej }
    887  1.1  thorpej 
    888  1.1  thorpej static int
    889  1.1  thorpej cdnr_add_filter(struct fltrinfo *fltrinfo)
    890  1.1  thorpej {
    891  1.1  thorpej 	struct cdnr_add_filter fltr_add;
    892  1.1  thorpej 
    893  1.1  thorpej 	memset(&fltr_add, 0, sizeof(fltr_add));
    894  1.1  thorpej 	strncpy(fltr_add.iface.cdnr_ifname,
    895  1.1  thorpej 		fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
    896  1.1  thorpej 	fltr_add.cdnr_handle = fltrinfo->clinfo->handle;
    897  1.1  thorpej 	fltr_add.filter = fltrinfo->fltr;
    898  1.1  thorpej 
    899  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_ADD_FILTER, &fltr_add) < 0)
    900  1.1  thorpej 		return (QOPERR_SYSCALL);
    901  1.1  thorpej 	fltrinfo->handle = fltr_add.filter_handle;
    902  1.1  thorpej 	return (0);
    903  1.1  thorpej }
    904  1.1  thorpej 
    905  1.1  thorpej static int
    906  1.1  thorpej cdnr_delete_filter(struct fltrinfo *fltrinfo)
    907  1.1  thorpej {
    908  1.1  thorpej 	struct cdnr_delete_filter fltr_del;
    909  1.1  thorpej 
    910  1.1  thorpej 	memset(&fltr_del, 0, sizeof(fltr_del));
    911  1.1  thorpej 	strncpy(fltr_del.iface.cdnr_ifname,
    912  1.1  thorpej 		fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
    913  1.1  thorpej 	fltr_del.filter_handle = fltrinfo->handle;
    914  1.1  thorpej 
    915  1.1  thorpej 	if (ioctl(cdnr_fd, CDNR_DEL_FILTER, &fltr_del) < 0)
    916  1.1  thorpej 		return (QOPERR_SYSCALL);
    917  1.1  thorpej 	return (0);
    918  1.1  thorpej }
    919  1.1  thorpej 
    920  1.1  thorpej 
    921  1.1  thorpej static int
    922  1.1  thorpej verify_tbprofile(struct tb_profile *profile, const char *cdnr_name)
    923  1.1  thorpej {
    924  1.1  thorpej 	if (profile->depth < 1500) {
    925  1.1  thorpej 		LOG(LOG_WARNING, 0,
    926  1.1  thorpej 		    "warning: token bucket depth for %s is too small (%d)\n",
    927  1.1  thorpej 		    cdnr_name, profile->depth);
    928  1.1  thorpej 		return (-1);
    929  1.1  thorpej 	}
    930  1.1  thorpej 	return (0);
    931  1.1  thorpej }
    932  1.1  thorpej 
    933