xref: /netbsd/usr.sbin/altq/libaltq/qop_cdnr.c (revision d5e1f166)
1*d5e1f166Sitojun /*	$NetBSD: qop_cdnr.c,v 1.4 2001/08/22 08:52:37 itojun Exp $	*/
2*d5e1f166Sitojun /*	$KAME: qop_cdnr.c,v 1.9 2001/08/16 10:39:14 kjc Exp $	*/
395a65560Sthorpej /*
495a65560Sthorpej  * Copyright (C) 1999-2000
595a65560Sthorpej  *	Sony Computer Science Laboratories, Inc.  All rights reserved.
695a65560Sthorpej  *
795a65560Sthorpej  * Redistribution and use in source and binary forms, with or without
895a65560Sthorpej  * modification, are permitted provided that the following conditions
995a65560Sthorpej  * are met:
1095a65560Sthorpej  * 1. Redistributions of source code must retain the above copyright
1195a65560Sthorpej  *    notice, this list of conditions and the following disclaimer.
1295a65560Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
1395a65560Sthorpej  *    notice, this list of conditions and the following disclaimer in the
1495a65560Sthorpej  *    documentation and/or other materials provided with the distribution.
1595a65560Sthorpej  *
1695a65560Sthorpej  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
1795a65560Sthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1895a65560Sthorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1995a65560Sthorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
2095a65560Sthorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2195a65560Sthorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2295a65560Sthorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2395a65560Sthorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2495a65560Sthorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2595a65560Sthorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2695a65560Sthorpej  * SUCH DAMAGE.
2795a65560Sthorpej  */
2895a65560Sthorpej 
2995a65560Sthorpej #include <sys/param.h>
3095a65560Sthorpej #include <sys/socket.h>
3195a65560Sthorpej #include <sys/sockio.h>
3295a65560Sthorpej #include <sys/ioctl.h>
3395a65560Sthorpej #include <sys/fcntl.h>
3495a65560Sthorpej #include <net/if.h>
3595a65560Sthorpej #include <netinet/in.h>
3695a65560Sthorpej #include <arpa/inet.h>
3795a65560Sthorpej 
3895a65560Sthorpej #include <stdio.h>
3995a65560Sthorpej #include <stdlib.h>
4095a65560Sthorpej #include <unistd.h>
4195a65560Sthorpej #include <stddef.h>
4295a65560Sthorpej #include <string.h>
4395a65560Sthorpej #include <ctype.h>
4495a65560Sthorpej #include <errno.h>
4595a65560Sthorpej #include <syslog.h>
4695a65560Sthorpej #include <netdb.h>
4795a65560Sthorpej 
4895a65560Sthorpej #include <altq/altq.h>
4995a65560Sthorpej #include <altq/altq_cdnr.h>
5095a65560Sthorpej #include "altq_qop.h"
5195a65560Sthorpej #include "qop_cdnr.h"
5295a65560Sthorpej /*
5395a65560Sthorpej  * diffserve traffic conditioner support
5495a65560Sthorpej  *
5595a65560Sthorpej  * we use the existing qop interface to support conditioner.
5695a65560Sthorpej  */
5795a65560Sthorpej 
588b8734d2Sitojun static struct ifinfo *cdnr_ifname2ifinfo(const char *);
598b8734d2Sitojun static int cdnr_attach(struct ifinfo *);
608b8734d2Sitojun static int cdnr_detach(struct ifinfo *);
618b8734d2Sitojun static int cdnr_enable(struct ifinfo *);
628b8734d2Sitojun static int cdnr_disable(struct ifinfo *);
638b8734d2Sitojun static int cdnr_add_class(struct classinfo *);
648b8734d2Sitojun static int cdnr_modify_class(struct classinfo *, void *);
658b8734d2Sitojun static int cdnr_delete_class(struct classinfo *);
668b8734d2Sitojun static int cdnr_add_filter(struct fltrinfo *);
678b8734d2Sitojun static int cdnr_delete_filter(struct fltrinfo *);
688b8734d2Sitojun static int verify_tbprofile(struct tb_profile *, const char *);
6995a65560Sthorpej 
7095a65560Sthorpej #define CDNR_DEVICE	"/dev/altq/cdnr"
7195a65560Sthorpej 
7295a65560Sthorpej static int cdnr_fd = -1;
7395a65560Sthorpej static int cdnr_refcount = 0;
7495a65560Sthorpej 
7595a65560Sthorpej static struct qdisc_ops cdnr_qdisc = {
7695a65560Sthorpej 	ALTQT_CDNR,
7795a65560Sthorpej 	"cdnr",
7895a65560Sthorpej 	cdnr_attach,
7995a65560Sthorpej 	cdnr_detach,
8095a65560Sthorpej 	NULL,			/* clear */
8195a65560Sthorpej 	cdnr_enable,
8295a65560Sthorpej 	cdnr_disable,
8395a65560Sthorpej 	cdnr_add_class,
8495a65560Sthorpej 	cdnr_modify_class,
8595a65560Sthorpej 	cdnr_delete_class,
8695a65560Sthorpej 	cdnr_add_filter,
8795a65560Sthorpej 	cdnr_delete_filter,
8895a65560Sthorpej };
8995a65560Sthorpej 
9095a65560Sthorpej u_long
cdnr_name2handle(const char * ifname,const char * cdnr_name)9195a65560Sthorpej cdnr_name2handle(const char *ifname, const char *cdnr_name)
9295a65560Sthorpej {
9395a65560Sthorpej 	struct ifinfo		*ifinfo;
9495a65560Sthorpej 	struct classinfo	*clinfo;
9595a65560Sthorpej 
9695a65560Sthorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
9795a65560Sthorpej 		return (CDNR_NULL_HANDLE);
9895a65560Sthorpej 
9995a65560Sthorpej 	if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
10095a65560Sthorpej 		return (CDNR_NULL_HANDLE);
10195a65560Sthorpej 
10295a65560Sthorpej 	return (clinfo->handle);
10395a65560Sthorpej }
10495a65560Sthorpej 
10595a65560Sthorpej static struct ifinfo *
cdnr_ifname2ifinfo(const char * ifname)10695a65560Sthorpej cdnr_ifname2ifinfo(const char *ifname)
10795a65560Sthorpej {
10895a65560Sthorpej 	struct ifinfo	*ifinfo;
10995a65560Sthorpej 	char input_ifname[64];
11095a65560Sthorpej 
11195a65560Sthorpej 	/*
11295a65560Sthorpej 	 * search for an existing input interface
11395a65560Sthorpej 	 */
11495a65560Sthorpej 	if ((ifinfo = input_ifname2ifinfo(ifname)) != NULL)
11595a65560Sthorpej 		return (ifinfo);
11695a65560Sthorpej 
11795a65560Sthorpej 	/*
11895a65560Sthorpej 	 * if there is a corresponding output interface,
11995a65560Sthorpej 	 * create an input interface by prepending "_" to
12095a65560Sthorpej 	 * its name.
12195a65560Sthorpej 	 */
12295a65560Sthorpej 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
12395a65560Sthorpej 		return (NULL);
12495a65560Sthorpej 
12595a65560Sthorpej 	input_ifname[0] = '_';
1268b8734d2Sitojun 	strlcpy(input_ifname+1, ifname, sizeof(input_ifname)-1);
12795a65560Sthorpej 	if (qop_add_if(&ifinfo, input_ifname, 0, &cdnr_qdisc, NULL) != 0) {
12895a65560Sthorpej 		LOG(LOG_ERR, errno,
129*d5e1f166Sitojun 		    "cdnr_ifname2ifinfo: can't add a input interface %s",
13095a65560Sthorpej 		    ifname);
13195a65560Sthorpej 		return (NULL);
13295a65560Sthorpej 	}
13395a65560Sthorpej 	return (ifinfo);
13495a65560Sthorpej }
13595a65560Sthorpej 
13695a65560Sthorpej int
qcmd_cdnr_add_element(struct tc_action * rp,const char * ifname,const char * cdnr_name,struct tc_action * action)13795a65560Sthorpej qcmd_cdnr_add_element(struct tc_action *rp, const char *ifname,
13895a65560Sthorpej 		   const char *cdnr_name, struct tc_action *action)
13995a65560Sthorpej {
14095a65560Sthorpej 	struct ifinfo		*ifinfo;
14195a65560Sthorpej 	struct classinfo	*clinfo;
14295a65560Sthorpej 	int error;
14395a65560Sthorpej 
14495a65560Sthorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
14595a65560Sthorpej 		return (QOPERR_BADIF);
14695a65560Sthorpej 
14795a65560Sthorpej 	if ((error = qop_cdnr_add_element(&clinfo, cdnr_name, ifinfo,
14895a65560Sthorpej 					  action)) != 0) {
149*d5e1f166Sitojun 		LOG(LOG_ERR, errno, "%s: add element failed!",
15095a65560Sthorpej 		    qoperror(error));
15195a65560Sthorpej 		return (error);
15295a65560Sthorpej 	}
15395a65560Sthorpej 
15495a65560Sthorpej 	if (rp != NULL) {
15595a65560Sthorpej 		rp->tca_code = TCACODE_HANDLE;
15695a65560Sthorpej 		rp->tca_handle = clinfo->handle;
15795a65560Sthorpej 	}
15895a65560Sthorpej 	return (0);
15995a65560Sthorpej }
16095a65560Sthorpej 
16195a65560Sthorpej int
qcmd_cdnr_add_tbmeter(struct tc_action * rp,const char * ifname,const char * cdnr_name,struct tb_profile * profile,struct tc_action * in_action,struct tc_action * out_action)16295a65560Sthorpej qcmd_cdnr_add_tbmeter(struct tc_action *rp, const char *ifname,
16395a65560Sthorpej 		      const char *cdnr_name,
16495a65560Sthorpej 		      struct tb_profile *profile,
16595a65560Sthorpej 		      struct tc_action *in_action,
16695a65560Sthorpej 		      struct tc_action *out_action)
16795a65560Sthorpej {
16895a65560Sthorpej 	struct ifinfo		*ifinfo;
16995a65560Sthorpej 	struct classinfo	*clinfo;
17095a65560Sthorpej 	int error;
17195a65560Sthorpej 
17295a65560Sthorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
17395a65560Sthorpej 		return (QOPERR_BADIF);
17495a65560Sthorpej 
17595a65560Sthorpej 	verify_tbprofile(profile, cdnr_name);
17695a65560Sthorpej 
17795a65560Sthorpej 	if ((error = qop_cdnr_add_tbmeter(&clinfo, cdnr_name, ifinfo,
17895a65560Sthorpej 				  profile, in_action, out_action)) != 0) {
179*d5e1f166Sitojun 		LOG(LOG_ERR, errno, "%s: add tbmeter failed!",
18095a65560Sthorpej 		    qoperror(error));
18195a65560Sthorpej 		return (error);
18295a65560Sthorpej 	}
18395a65560Sthorpej 
18495a65560Sthorpej 	if (rp != NULL) {
18595a65560Sthorpej 		rp->tca_code = TCACODE_HANDLE;
18695a65560Sthorpej 		rp->tca_handle = clinfo->handle;
18795a65560Sthorpej 	}
18895a65560Sthorpej 	return (0);
18995a65560Sthorpej }
19095a65560Sthorpej 
19195a65560Sthorpej int
qcmd_cdnr_add_trtcm(struct tc_action * rp,const char * ifname,const char * cdnr_name,struct tb_profile * cmtd_profile,struct tb_profile * peak_profile,struct tc_action * green_action,struct tc_action * yellow_action,struct tc_action * red_action,int coloraware)19295a65560Sthorpej qcmd_cdnr_add_trtcm(struct tc_action *rp, const char *ifname,
19395a65560Sthorpej 		    const char *cdnr_name,
19495a65560Sthorpej 		    struct tb_profile *cmtd_profile,
19595a65560Sthorpej 		    struct tb_profile *peak_profile,
19695a65560Sthorpej 		    struct tc_action *green_action,
19795a65560Sthorpej 		    struct tc_action *yellow_action,
19895a65560Sthorpej 		    struct tc_action *red_action, int coloraware)
19995a65560Sthorpej {
20095a65560Sthorpej 	struct ifinfo		*ifinfo;
20195a65560Sthorpej 	struct classinfo	*clinfo;
20295a65560Sthorpej 	int error;
20395a65560Sthorpej 
20495a65560Sthorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
20595a65560Sthorpej 		return (QOPERR_BADIF);
20695a65560Sthorpej 
20795a65560Sthorpej 	verify_tbprofile(cmtd_profile, cdnr_name);
20895a65560Sthorpej 	verify_tbprofile(peak_profile, cdnr_name);
20995a65560Sthorpej 
21095a65560Sthorpej 	if ((error = qop_cdnr_add_trtcm(&clinfo, cdnr_name, ifinfo,
21195a65560Sthorpej 			  cmtd_profile, peak_profile,
21295a65560Sthorpej 			  green_action, yellow_action, red_action,
21395a65560Sthorpej 	     		  coloraware)) != 0) {
214*d5e1f166Sitojun 		LOG(LOG_ERR, errno, "%s: add trtcm failed!",
21595a65560Sthorpej 		    qoperror(error));
21695a65560Sthorpej 		return (error);
21795a65560Sthorpej 	}
21895a65560Sthorpej 
21995a65560Sthorpej 	if (rp != NULL) {
22095a65560Sthorpej 		rp->tca_code = TCACODE_HANDLE;
22195a65560Sthorpej 		rp->tca_handle = clinfo->handle;
22295a65560Sthorpej 	}
22395a65560Sthorpej 	return (0);
22495a65560Sthorpej }
22595a65560Sthorpej 
22695a65560Sthorpej int
qcmd_cdnr_add_tswtcm(struct tc_action * rp,const char * ifname,const char * cdnr_name,const u_int32_t cmtd_rate,const u_int32_t peak_rate,const u_int32_t avg_interval,struct tc_action * green_action,struct tc_action * yellow_action,struct tc_action * red_action)22795a65560Sthorpej qcmd_cdnr_add_tswtcm(struct tc_action *rp, const char *ifname,
22895a65560Sthorpej 		     const char *cdnr_name, const u_int32_t cmtd_rate,
22995a65560Sthorpej 		     const u_int32_t peak_rate, const u_int32_t avg_interval,
23095a65560Sthorpej 		     struct tc_action *green_action,
23195a65560Sthorpej 		     struct tc_action *yellow_action,
23295a65560Sthorpej 		     struct tc_action *red_action)
23395a65560Sthorpej {
23495a65560Sthorpej 	struct ifinfo		*ifinfo;
23595a65560Sthorpej 	struct classinfo	*clinfo;
23695a65560Sthorpej 	int error;
23795a65560Sthorpej 
23895a65560Sthorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
23995a65560Sthorpej 		return (QOPERR_BADIF);
24095a65560Sthorpej 
24195a65560Sthorpej 	if (cmtd_rate > peak_rate) {
24295a65560Sthorpej 		LOG(LOG_ERR, 0,
243*d5e1f166Sitojun 		    "add tswtcm: cmtd_rate larger than peak_rate!");
24495a65560Sthorpej 		return (QOPERR_INVAL);
24595a65560Sthorpej 	}
24695a65560Sthorpej 
24795a65560Sthorpej 	if ((error = qop_cdnr_add_tswtcm(&clinfo, cdnr_name, ifinfo,
24895a65560Sthorpej 					cmtd_rate, peak_rate, avg_interval,
24995a65560Sthorpej 					green_action, yellow_action,
25095a65560Sthorpej 					red_action)) != 0) {
251*d5e1f166Sitojun 		LOG(LOG_ERR, errno, "%s: add tswtcm failed!",
25295a65560Sthorpej 		    qoperror(error));
25395a65560Sthorpej 		return (error);
25495a65560Sthorpej 	}
25595a65560Sthorpej 
25695a65560Sthorpej 	if (rp != NULL) {
25795a65560Sthorpej 		rp->tca_code = TCACODE_HANDLE;
25895a65560Sthorpej 		rp->tca_handle = clinfo->handle;
25995a65560Sthorpej 	}
26095a65560Sthorpej 	return (0);
26195a65560Sthorpej }
26295a65560Sthorpej 
26395a65560Sthorpej int
qcmd_cdnr_delete(const char * ifname,const char * cdnr_name)26495a65560Sthorpej qcmd_cdnr_delete(const char *ifname, const char *cdnr_name)
26595a65560Sthorpej {
26695a65560Sthorpej 	struct ifinfo		*ifinfo;
26795a65560Sthorpej 	struct classinfo	*clinfo;
26895a65560Sthorpej 
26995a65560Sthorpej 	if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
27095a65560Sthorpej 		return (QOPERR_BADIF);
27195a65560Sthorpej 
27295a65560Sthorpej 	if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
27395a65560Sthorpej 		return (QOPERR_BADCLASS);
27495a65560Sthorpej 
27595a65560Sthorpej 	return qop_delete_cdnr(clinfo);
27695a65560Sthorpej }
27795a65560Sthorpej 
27895a65560Sthorpej /*
27995a65560Sthorpej  * class operations:
28095a65560Sthorpej  *	class structure is used to hold conditioners.
28195a65560Sthorpej  *	XXX
28295a65560Sthorpej  *	conditioners has dependencies in the reverse order; parent nodes
28395a65560Sthorpej  *	refere to child nodes, and thus, a child is created first and
28495a65560Sthorpej  *	parents should be removed first.
28595a65560Sthorpej  *	qop_add_cdnr() and qop_delete_cdnr() are wrapper functions
28695a65560Sthorpej  *	of qop_add_class() and qop_delete_class(), and takes care
28795a65560Sthorpej  *	of dependencies.
28895a65560Sthorpej  *	1. when adding a conditioner, it is created as a child of a
28995a65560Sthorpej  *	   dummy root class.  then, the child conditioners are made
29095a65560Sthorpej  *	   as its children.
29195a65560Sthorpej  *	2. when deleting a conditioner, its child conditioners are made
29295a65560Sthorpej  *	   as children of the dummy root class.  then, the conditioner
29395a65560Sthorpej  *	   is deleted.
29495a65560Sthorpej  */
29595a65560Sthorpej 
29695a65560Sthorpej int
qop_add_cdnr(struct classinfo ** rp,const char * cdnr_name,struct ifinfo * ifinfo,struct classinfo ** childlist,void * cdnr_private)29795a65560Sthorpej qop_add_cdnr(struct classinfo **rp, const char *cdnr_name,
29895a65560Sthorpej 	     struct ifinfo *ifinfo, struct classinfo **childlist,
29995a65560Sthorpej 	     void *cdnr_private)
30095a65560Sthorpej {
30195a65560Sthorpej 	struct classinfo	*clinfo, *root, *cl, *prev;
30295a65560Sthorpej 	int error;
30395a65560Sthorpej 
30495a65560Sthorpej 	/*
30595a65560Sthorpej 	 * if there is no root cdnr, create one.
30695a65560Sthorpej 	 */
30795a65560Sthorpej 	if ((root = get_rootclass(ifinfo)) == NULL) {
30895a65560Sthorpej 		if ((error = qop_add_class(&root, "cdnr_root",
30995a65560Sthorpej 					   ifinfo, NULL, NULL)) != 0) {
31095a65560Sthorpej 			LOG(LOG_ERR, errno,
311*d5e1f166Sitojun 			    "cdnr: %s: can't create dummy root cdnr on %s!",
31295a65560Sthorpej 			    qoperror(error), ifinfo->ifname);
31395a65560Sthorpej 			return (QOPERR_CLASS);
31495a65560Sthorpej 		}
31595a65560Sthorpej 	}
31695a65560Sthorpej 
31795a65560Sthorpej 	/*
31895a65560Sthorpej 	 * create a class as a child of a root class.
31995a65560Sthorpej 	 */
32095a65560Sthorpej 	if ((error = qop_add_class(&clinfo, cdnr_name,
32195a65560Sthorpej 				   ifinfo, root, cdnr_private)) != 0)
32295a65560Sthorpej 		return (error);
32395a65560Sthorpej 	/*
32495a65560Sthorpej 	 * move child nodes
32595a65560Sthorpej 	 */
32695a65560Sthorpej 	for (cl = *childlist; cl != NULL; cl = *++childlist) {
32795a65560Sthorpej 		if (cl->parent != root) {
32895a65560Sthorpej 			/*
32995a65560Sthorpej 			 * this conditioner already has a non-root parent.
33095a65560Sthorpej 			 * we can't track down a multi-parent node by a
33195a65560Sthorpej 			 * tree structure; leave it as it is.
33295a65560Sthorpej 			 * (we need a mechanism similar to a symbolic link
33395a65560Sthorpej 			 * in a file system)
33495a65560Sthorpej 			 */
33595a65560Sthorpej 			continue;
33695a65560Sthorpej 		}
33795a65560Sthorpej 		/* remove this child from the root */
33895a65560Sthorpej 		if (root->child == cl)
33995a65560Sthorpej 			root->child = cl->sibling;
34095a65560Sthorpej 		else for (prev = root->child;
34195a65560Sthorpej 			  prev->sibling != NULL; prev = prev->sibling)
34295a65560Sthorpej 			if (prev->sibling == cl) {
34395a65560Sthorpej 				prev->sibling = cl->sibling;
34495a65560Sthorpej 				break;
34595a65560Sthorpej 			}
34695a65560Sthorpej 
34795a65560Sthorpej 		/* add as a child */
34895a65560Sthorpej 		cl->sibling = clinfo->child;
34995a65560Sthorpej 		clinfo->child = cl;
35095a65560Sthorpej 		cl->parent = clinfo;
35195a65560Sthorpej 	}
35295a65560Sthorpej 
35395a65560Sthorpej 	if (rp != NULL)
35495a65560Sthorpej 		*rp = clinfo;
35595a65560Sthorpej 	return (0);
35695a65560Sthorpej }
35795a65560Sthorpej 
35895a65560Sthorpej int
qop_delete_cdnr(struct classinfo * clinfo)35995a65560Sthorpej qop_delete_cdnr(struct classinfo *clinfo)
36095a65560Sthorpej {
36195a65560Sthorpej 	struct classinfo *cl, *root;
36295a65560Sthorpej 	int error;
36395a65560Sthorpej 
36495a65560Sthorpej 	if ((root = get_rootclass(clinfo->ifinfo)) == NULL) {
365*d5e1f166Sitojun 		LOG(LOG_ERR, 0, "qop_delete_cdnr: no root cdnr!");
36695a65560Sthorpej 		return (QOPERR_CLASS);
36795a65560Sthorpej 	}
36895a65560Sthorpej 
36995a65560Sthorpej 	if (clinfo->parent != root)
37095a65560Sthorpej 		return (QOPERR_CLASS_PERM);
37195a65560Sthorpej 
37295a65560Sthorpej 	if ((cl = clinfo->child) != NULL) {
37395a65560Sthorpej 		/* change child's parent to root, find the last child */
37495a65560Sthorpej 		while (cl->sibling != NULL) {
37595a65560Sthorpej 			cl->parent = root;
37695a65560Sthorpej 			cl = cl->sibling;
37795a65560Sthorpej 		}
37895a65560Sthorpej 		cl->parent = root;
37995a65560Sthorpej 
38095a65560Sthorpej 		/* move children to siblings */
38195a65560Sthorpej 		cl->sibling = clinfo->sibling;
38295a65560Sthorpej 		clinfo->sibling = cl;
38395a65560Sthorpej 		clinfo->child = NULL;
38495a65560Sthorpej 	}
38595a65560Sthorpej 
38695a65560Sthorpej 	error = qop_delete_class(clinfo);
38795a65560Sthorpej 
38895a65560Sthorpej 	if (error) {
38995a65560Sthorpej 		/* ick! restore the class tree */
39095a65560Sthorpej 		if (cl != NULL) {
39195a65560Sthorpej 			clinfo->child = clinfo->sibling;
39295a65560Sthorpej 			clinfo->sibling = cl->sibling;
39395a65560Sthorpej 			cl->sibling = NULL;
39495a65560Sthorpej 			/* restore parent field */
39595a65560Sthorpej 			for (cl = clinfo->child; cl != NULL; cl = cl->sibling)
39695a65560Sthorpej 				cl->parent = clinfo;
39795a65560Sthorpej 		}
39895a65560Sthorpej 	}
39995a65560Sthorpej 	return (error);
40095a65560Sthorpej }
40195a65560Sthorpej 
40295a65560Sthorpej int
qop_cdnr_add_element(struct classinfo ** rp,const char * cdnr_name,struct ifinfo * ifinfo,struct tc_action * action)40395a65560Sthorpej qop_cdnr_add_element(struct classinfo **rp, const char *cdnr_name,
40495a65560Sthorpej 		     struct ifinfo *ifinfo, struct tc_action *action)
40595a65560Sthorpej {
40695a65560Sthorpej 	struct classinfo *clinfo, *clist[2];
40795a65560Sthorpej 	struct cdnrinfo *cdnrinfo = NULL;
40895a65560Sthorpej 	int error;
40995a65560Sthorpej 
41095a65560Sthorpej 	if (action->tca_code == TCACODE_HANDLE) {
41195a65560Sthorpej 		clinfo = clhandle2clinfo(ifinfo, action->tca_handle);
41295a65560Sthorpej 		if (clinfo == NULL)
41395a65560Sthorpej 			return (QOPERR_BADCLASS);
41495a65560Sthorpej 		clist[0] = clinfo;
41595a65560Sthorpej 		clist[1] = NULL;
41695a65560Sthorpej #if 1
41795a65560Sthorpej 		/*
41895a65560Sthorpej 		 * if the conditioner referred to doesn't have a name,
41995a65560Sthorpej 		 * this is called just to add a name to it.
42095a65560Sthorpej 		 * we can simply add the name to the existing conditioner
42195a65560Sthorpej 		 * and return it.
42295a65560Sthorpej 		 */
42395a65560Sthorpej 		if (cdnr_name != NULL &&
42495a65560Sthorpej 		    strcmp(clinfo->clname, "(null)") == 0) {
42595a65560Sthorpej 			free(clinfo->clname);
42695a65560Sthorpej 			clinfo->clname = strdup(cdnr_name);
42795a65560Sthorpej 			if (rp != NULL)
42895a65560Sthorpej 				*rp = clinfo;
42995a65560Sthorpej 			return (0);
43095a65560Sthorpej 		}
43195a65560Sthorpej #endif
43295a65560Sthorpej 	} else
43395a65560Sthorpej 		clist[0] = NULL;
43495a65560Sthorpej 
43595a65560Sthorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
43695a65560Sthorpej 		return (QOPERR_NOMEM);
43795a65560Sthorpej 
43895a65560Sthorpej 	cdnrinfo->tce_type = TCETYPE_ELEMENT;
43995a65560Sthorpej 	cdnrinfo->tce_un.element.action = *action;
44095a65560Sthorpej 
44195a65560Sthorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
44295a65560Sthorpej 				  cdnrinfo)) != 0)
44395a65560Sthorpej 		goto err_ret;
44495a65560Sthorpej 
44595a65560Sthorpej 	if (rp != NULL)
44695a65560Sthorpej 		*rp = clinfo;
44795a65560Sthorpej 	return (0);
44895a65560Sthorpej 
44995a65560Sthorpej  err_ret:
45095a65560Sthorpej 	if (cdnrinfo != NULL)
45195a65560Sthorpej 		free(cdnrinfo);
45295a65560Sthorpej 	return (error);
45395a65560Sthorpej }
45495a65560Sthorpej 
45595a65560Sthorpej int
qop_cdnr_add_tbmeter(struct classinfo ** rp,const char * cdnr_name,struct ifinfo * ifinfo,struct tb_profile * profile,struct tc_action * in_action,struct tc_action * out_action)45695a65560Sthorpej qop_cdnr_add_tbmeter(struct classinfo **rp, const char *cdnr_name,
45795a65560Sthorpej 		     struct ifinfo *ifinfo,
45895a65560Sthorpej 		     struct tb_profile *profile,
45995a65560Sthorpej 		     struct tc_action *in_action,
46095a65560Sthorpej 		     struct tc_action *out_action)
46195a65560Sthorpej {
46295a65560Sthorpej 	struct classinfo *clinfo, *clist[3];
46395a65560Sthorpej 	struct cdnrinfo *cdnrinfo = NULL;
46495a65560Sthorpej 	int n, error;
46595a65560Sthorpej 
46695a65560Sthorpej 	n = 0;
46795a65560Sthorpej 	if (in_action->tca_code == TCACODE_HANDLE) {
46895a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, in_action->tca_handle);
46995a65560Sthorpej 		if (clist[n] == NULL)
47095a65560Sthorpej 			return (QOPERR_BADCLASS);
47195a65560Sthorpej 		n++;
47295a65560Sthorpej 	}
47395a65560Sthorpej 	if (out_action->tca_code == TCACODE_HANDLE) {
47495a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, out_action->tca_handle);
47595a65560Sthorpej 		if (clist[n] == NULL)
47695a65560Sthorpej 			return (QOPERR_BADCLASS);
47795a65560Sthorpej 		n++;
47895a65560Sthorpej 	}
47995a65560Sthorpej 	clist[n] = NULL;
48095a65560Sthorpej 
48195a65560Sthorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
48295a65560Sthorpej 		return (QOPERR_NOMEM);
48395a65560Sthorpej 
48495a65560Sthorpej 	cdnrinfo->tce_type = TCETYPE_TBMETER;
48595a65560Sthorpej 	cdnrinfo->tce_un.tbmeter.profile = *profile;
48695a65560Sthorpej 	cdnrinfo->tce_un.tbmeter.in_action = *in_action;
48795a65560Sthorpej 	cdnrinfo->tce_un.tbmeter.out_action = *out_action;
48895a65560Sthorpej 
48995a65560Sthorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
49095a65560Sthorpej 				   cdnrinfo)) != 0)
49195a65560Sthorpej 		goto err_ret;
49295a65560Sthorpej 
49395a65560Sthorpej 	if (rp != NULL)
49495a65560Sthorpej 		*rp = clinfo;
49595a65560Sthorpej 	return (0);
49695a65560Sthorpej 
49795a65560Sthorpej  err_ret:
49895a65560Sthorpej 	if (cdnrinfo != NULL)
49995a65560Sthorpej 		free(cdnrinfo);
50095a65560Sthorpej 	return (error);
50195a65560Sthorpej }
50295a65560Sthorpej 
50395a65560Sthorpej int
qop_cdnr_modify_tbmeter(struct classinfo * clinfo,struct tb_profile * profile)50495a65560Sthorpej qop_cdnr_modify_tbmeter(struct classinfo *clinfo, struct tb_profile *profile)
50595a65560Sthorpej {
50695a65560Sthorpej 	struct cdnrinfo *cdnrinfo = clinfo->private;
50795a65560Sthorpej 
50895a65560Sthorpej 	if (cdnrinfo->tce_type != TCETYPE_TBMETER)
50995a65560Sthorpej 		return (QOPERR_CLASS_INVAL);
51095a65560Sthorpej 	cdnrinfo->tce_un.tbmeter.profile = *profile;
51195a65560Sthorpej 
51295a65560Sthorpej 	return qop_modify_class(clinfo, NULL);
51395a65560Sthorpej }
51495a65560Sthorpej 
51595a65560Sthorpej int
qop_cdnr_add_trtcm(struct classinfo ** rp,const char * cdnr_name,struct ifinfo * ifinfo,struct tb_profile * cmtd_profile,struct tb_profile * peak_profile,struct tc_action * green_action,struct tc_action * yellow_action,struct tc_action * red_action,int coloraware)51695a65560Sthorpej qop_cdnr_add_trtcm(struct classinfo **rp, const char *cdnr_name,
51795a65560Sthorpej 		   struct ifinfo *ifinfo,
51895a65560Sthorpej 		   struct tb_profile *cmtd_profile,
51995a65560Sthorpej 		   struct tb_profile *peak_profile,
52095a65560Sthorpej 		   struct tc_action *green_action,
52195a65560Sthorpej 		   struct tc_action *yellow_action,
52295a65560Sthorpej 		   struct tc_action *red_action, int coloraware)
52395a65560Sthorpej {
52495a65560Sthorpej 	struct classinfo *clinfo, *clist[4];
52595a65560Sthorpej 	struct cdnrinfo *cdnrinfo = NULL;
52695a65560Sthorpej 	int n, error;
52795a65560Sthorpej 
52895a65560Sthorpej 	n = 0;
52995a65560Sthorpej 	if (green_action->tca_code == TCACODE_HANDLE) {
53095a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
53195a65560Sthorpej 		if (clist[n] == NULL)
53295a65560Sthorpej 			return (QOPERR_BADCLASS);
53395a65560Sthorpej 		n++;
53495a65560Sthorpej 	}
53595a65560Sthorpej 	if (yellow_action->tca_code == TCACODE_HANDLE) {
53695a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
53795a65560Sthorpej 		if (clist[n] == NULL)
53895a65560Sthorpej 			return (QOPERR_BADCLASS);
53995a65560Sthorpej 		n++;
54095a65560Sthorpej 	}
54195a65560Sthorpej 	if (red_action->tca_code == TCACODE_HANDLE) {
54295a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
54395a65560Sthorpej 		if (clist[n] == NULL)
54495a65560Sthorpej 			return (QOPERR_BADCLASS);
54595a65560Sthorpej 		n++;
54695a65560Sthorpej 	}
54795a65560Sthorpej 	clist[n] = NULL;
54895a65560Sthorpej 
54995a65560Sthorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
55095a65560Sthorpej 		return (QOPERR_NOMEM);
55195a65560Sthorpej 
55295a65560Sthorpej 	cdnrinfo->tce_type = TCETYPE_TRTCM;
55395a65560Sthorpej 	cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
55495a65560Sthorpej 	cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
55595a65560Sthorpej 	cdnrinfo->tce_un.trtcm.green_action = *green_action;
55695a65560Sthorpej 	cdnrinfo->tce_un.trtcm.yellow_action = *yellow_action;
55795a65560Sthorpej 	cdnrinfo->tce_un.trtcm.red_action = *red_action;
55895a65560Sthorpej 	cdnrinfo->tce_un.trtcm.coloraware = coloraware;
55995a65560Sthorpej 
56095a65560Sthorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
56195a65560Sthorpej 				  cdnrinfo)) != 0)
56295a65560Sthorpej 		goto err_ret;
56395a65560Sthorpej 
56495a65560Sthorpej 	if (rp != NULL)
56595a65560Sthorpej 		*rp = clinfo;
56695a65560Sthorpej 	return (0);
56795a65560Sthorpej 
56895a65560Sthorpej  err_ret:
56995a65560Sthorpej 	if (cdnrinfo != NULL)
57095a65560Sthorpej 		free(cdnrinfo);
57195a65560Sthorpej 	return (error);
57295a65560Sthorpej }
57395a65560Sthorpej 
57495a65560Sthorpej int
qop_cdnr_modify_trtcm(struct classinfo * clinfo,struct tb_profile * cmtd_profile,struct tb_profile * peak_profile,int coloraware)57595a65560Sthorpej qop_cdnr_modify_trtcm(struct classinfo *clinfo,
57695a65560Sthorpej 		      struct tb_profile *cmtd_profile,
57795a65560Sthorpej 		      struct tb_profile *peak_profile, int coloraware)
57895a65560Sthorpej {
57995a65560Sthorpej 	struct cdnrinfo *cdnrinfo = clinfo->private;
58095a65560Sthorpej 
58195a65560Sthorpej 	if (cdnrinfo->tce_type != TCETYPE_TRTCM)
58295a65560Sthorpej 		return (QOPERR_CLASS_INVAL);
58395a65560Sthorpej 	cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
58495a65560Sthorpej 	cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
58595a65560Sthorpej 	cdnrinfo->tce_un.trtcm.coloraware = coloraware;
58695a65560Sthorpej 
58795a65560Sthorpej 	return qop_modify_class(clinfo, NULL);
58895a65560Sthorpej }
58995a65560Sthorpej 
59095a65560Sthorpej int
qop_cdnr_add_tswtcm(struct classinfo ** rp,const char * cdnr_name,struct ifinfo * ifinfo,const u_int32_t cmtd_rate,const u_int32_t peak_rate,const u_int32_t avg_interval,struct tc_action * green_action,struct tc_action * yellow_action,struct tc_action * red_action)59195a65560Sthorpej qop_cdnr_add_tswtcm(struct classinfo **rp, const char *cdnr_name,
59295a65560Sthorpej 		    struct ifinfo *ifinfo, const u_int32_t cmtd_rate,
59395a65560Sthorpej 		    const u_int32_t peak_rate, const u_int32_t avg_interval,
59495a65560Sthorpej 		    struct tc_action *green_action,
59595a65560Sthorpej 		    struct tc_action *yellow_action,
59695a65560Sthorpej 		    struct tc_action *red_action)
59795a65560Sthorpej {
59895a65560Sthorpej 	struct classinfo *clinfo, *clist[4];
59995a65560Sthorpej 	struct cdnrinfo *cdnrinfo = NULL;
60095a65560Sthorpej 	int n, error;
60195a65560Sthorpej 
60295a65560Sthorpej 	n = 0;
60395a65560Sthorpej 	if (green_action->tca_code == TCACODE_HANDLE) {
60495a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
60595a65560Sthorpej 		if (clist[n] == NULL)
60695a65560Sthorpej 			return (QOPERR_BADCLASS);
60795a65560Sthorpej 		n++;
60895a65560Sthorpej 	}
60995a65560Sthorpej 	if (yellow_action->tca_code == TCACODE_HANDLE) {
61095a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
61195a65560Sthorpej 		if (clist[n] == NULL)
61295a65560Sthorpej 			return (QOPERR_BADCLASS);
61395a65560Sthorpej 		n++;
61495a65560Sthorpej 	}
61595a65560Sthorpej 	if (red_action->tca_code == TCACODE_HANDLE) {
61695a65560Sthorpej 		clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
61795a65560Sthorpej 		if (clist[n] == NULL)
61895a65560Sthorpej 			return (QOPERR_BADCLASS);
61995a65560Sthorpej 		n++;
62095a65560Sthorpej 	}
62195a65560Sthorpej 	clist[n] = NULL;
62295a65560Sthorpej 
62395a65560Sthorpej 	if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
62495a65560Sthorpej 		return (QOPERR_NOMEM);
62595a65560Sthorpej 
62695a65560Sthorpej 	cdnrinfo->tce_type = TCETYPE_TSWTCM;
62795a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
62895a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
62995a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
63095a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.green_action = *green_action;
63195a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.yellow_action = *yellow_action;
63295a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.red_action = *red_action;
63395a65560Sthorpej 
63495a65560Sthorpej 	if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
63595a65560Sthorpej 				  cdnrinfo)) != 0)
63695a65560Sthorpej 		goto err_ret;
63795a65560Sthorpej 
63895a65560Sthorpej 	if (rp != NULL)
63995a65560Sthorpej 		*rp = clinfo;
64095a65560Sthorpej 	return (0);
64195a65560Sthorpej 
64295a65560Sthorpej  err_ret:
64395a65560Sthorpej 	if (cdnrinfo != NULL)
64495a65560Sthorpej 		free(cdnrinfo);
64595a65560Sthorpej 	return (error);
64695a65560Sthorpej }
64795a65560Sthorpej 
64895a65560Sthorpej int
qop_cdnr_modify_tswtcm(struct classinfo * clinfo,const u_int32_t cmtd_rate,const u_int32_t peak_rate,const u_int32_t avg_interval)64995a65560Sthorpej qop_cdnr_modify_tswtcm(struct classinfo *clinfo, const u_int32_t cmtd_rate,
65095a65560Sthorpej 		       const u_int32_t peak_rate, const u_int32_t avg_interval)
65195a65560Sthorpej {
65295a65560Sthorpej 	struct cdnrinfo *cdnrinfo = clinfo->private;
65395a65560Sthorpej 
65495a65560Sthorpej 	if (cdnrinfo->tce_type != TCETYPE_TSWTCM)
65595a65560Sthorpej 		return (QOPERR_CLASS_INVAL);
65695a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
65795a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
65895a65560Sthorpej 	cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
65995a65560Sthorpej 
66095a65560Sthorpej 	return qop_modify_class(clinfo, NULL);
66195a65560Sthorpej }
66295a65560Sthorpej 
66395a65560Sthorpej /*
66495a65560Sthorpej  *  system call interfaces for qdisc_ops
66595a65560Sthorpej  */
66695a65560Sthorpej static int
cdnr_attach(struct ifinfo * ifinfo)66795a65560Sthorpej cdnr_attach(struct ifinfo *ifinfo)
66895a65560Sthorpej {
66995a65560Sthorpej 	struct cdnr_interface iface;
67095a65560Sthorpej 
67195a65560Sthorpej 	if (cdnr_fd < 0 &&
67295a65560Sthorpej 	    (cdnr_fd = open(CDNR_DEVICE, O_RDWR)) < 0 &&
67395a65560Sthorpej 	    (cdnr_fd = open_module(CDNR_DEVICE, O_RDWR)) < 0) {
674*d5e1f166Sitojun 		LOG(LOG_ERR, errno, "CDNR open");
67595a65560Sthorpej 		return (QOPERR_SYSCALL);
67695a65560Sthorpej 	}
67795a65560Sthorpej 
67895a65560Sthorpej 	cdnr_refcount++;
67995a65560Sthorpej 	memset(&iface, 0, sizeof(iface));
68095a65560Sthorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
68195a65560Sthorpej 
68295a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_IF_ATTACH, &iface) < 0)
68395a65560Sthorpej 		return (QOPERR_SYSCALL);
68495a65560Sthorpej #if 1
685*d5e1f166Sitojun 	LOG(LOG_INFO, 0, "conditioner attached to %s", iface.cdnr_ifname);
68695a65560Sthorpej #endif
68795a65560Sthorpej 	return (0);
68895a65560Sthorpej }
68995a65560Sthorpej 
69095a65560Sthorpej static int
cdnr_detach(struct ifinfo * ifinfo)69195a65560Sthorpej cdnr_detach(struct ifinfo *ifinfo)
69295a65560Sthorpej {
69395a65560Sthorpej 	struct cdnr_interface iface;
69495a65560Sthorpej 
69595a65560Sthorpej 	memset(&iface, 0, sizeof(iface));
69695a65560Sthorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
69795a65560Sthorpej 
69895a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_IF_DETACH, &iface) < 0)
69995a65560Sthorpej 		return (QOPERR_SYSCALL);
70095a65560Sthorpej 
70195a65560Sthorpej 	if (--cdnr_refcount == 0) {
70295a65560Sthorpej 		close(cdnr_fd);
70395a65560Sthorpej 		cdnr_fd = -1;
70495a65560Sthorpej 	}
70595a65560Sthorpej 	return (0);
70695a65560Sthorpej }
70795a65560Sthorpej 
70895a65560Sthorpej static int
cdnr_enable(struct ifinfo * ifinfo)70995a65560Sthorpej cdnr_enable(struct ifinfo *ifinfo)
71095a65560Sthorpej {
71195a65560Sthorpej 	struct cdnr_interface iface;
71295a65560Sthorpej 
71395a65560Sthorpej 	memset(&iface, 0, sizeof(iface));
71495a65560Sthorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
71595a65560Sthorpej 
71695a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_ENABLE, &iface) < 0)
71795a65560Sthorpej 		return (QOPERR_SYSCALL);
71895a65560Sthorpej 	return (0);
71995a65560Sthorpej }
72095a65560Sthorpej 
72195a65560Sthorpej static int
cdnr_disable(struct ifinfo * ifinfo)72295a65560Sthorpej cdnr_disable(struct ifinfo *ifinfo)
72395a65560Sthorpej {
72495a65560Sthorpej 	struct cdnr_interface iface;
72595a65560Sthorpej 
72695a65560Sthorpej 	memset(&iface, 0, sizeof(iface));
72795a65560Sthorpej 	strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
72895a65560Sthorpej 
72995a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_DISABLE, &iface) < 0)
73095a65560Sthorpej 		return (QOPERR_SYSCALL);
73195a65560Sthorpej 	return (0);
73295a65560Sthorpej }
73395a65560Sthorpej 
73495a65560Sthorpej static int
cdnr_add_class(struct classinfo * clinfo)73595a65560Sthorpej cdnr_add_class(struct classinfo *clinfo)
73695a65560Sthorpej {
73795a65560Sthorpej 	struct cdnr_add_element element_add;
73895a65560Sthorpej 	struct cdnr_add_tbmeter tbmeter_add;
73995a65560Sthorpej 	struct cdnr_add_trtcm   trtcm_add;
74095a65560Sthorpej 	struct cdnr_add_tswtcm  tswtcm_add;
74195a65560Sthorpej 	struct cdnrinfo *cdnrinfo;
74295a65560Sthorpej 
74395a65560Sthorpej 	cdnrinfo = clinfo->private;
74495a65560Sthorpej 
74595a65560Sthorpej 	/* root class is a dummy class */
74695a65560Sthorpej 	if (clinfo->parent == NULL) {
74795a65560Sthorpej 		clinfo->handle = 0;
74895a65560Sthorpej 		return (0);
74995a65560Sthorpej 	}
75095a65560Sthorpej 
75195a65560Sthorpej 	switch (cdnrinfo->tce_type) {
75295a65560Sthorpej 	case TCETYPE_ELEMENT:
75395a65560Sthorpej 		memset(&element_add, 0, sizeof(element_add));
75495a65560Sthorpej 		strncpy(element_add.iface.cdnr_ifname,
75595a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
75695a65560Sthorpej 		element_add.action = cdnrinfo->tce_un.element.action;
75795a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_ADD_ELEM, &element_add) < 0) {
75895a65560Sthorpej 			clinfo->handle = CDNR_NULL_HANDLE;
75995a65560Sthorpej 			return (QOPERR_SYSCALL);
76095a65560Sthorpej 		}
76195a65560Sthorpej 		clinfo->handle = element_add.cdnr_handle;
76295a65560Sthorpej 		break;
76395a65560Sthorpej 
76495a65560Sthorpej 	case TCETYPE_TBMETER:
76595a65560Sthorpej 		memset(&tbmeter_add, 0, sizeof(tbmeter_add));
76695a65560Sthorpej 		strncpy(tbmeter_add.iface.cdnr_ifname,
76795a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
76895a65560Sthorpej 		tbmeter_add.profile = cdnrinfo->tce_un.tbmeter.profile;
76995a65560Sthorpej 		tbmeter_add.in_action = cdnrinfo->tce_un.tbmeter.in_action;
77095a65560Sthorpej 		tbmeter_add.out_action = cdnrinfo->tce_un.tbmeter.out_action;
77195a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_ADD_TBM, &tbmeter_add) < 0) {
77295a65560Sthorpej 			clinfo->handle = CDNR_NULL_HANDLE;
77395a65560Sthorpej 			return (QOPERR_SYSCALL);
77495a65560Sthorpej 		}
77595a65560Sthorpej 		clinfo->handle = tbmeter_add.cdnr_handle;
77695a65560Sthorpej 		break;
77795a65560Sthorpej 
77895a65560Sthorpej 	case TCETYPE_TRTCM:
77995a65560Sthorpej 		memset(&trtcm_add, 0, sizeof(trtcm_add));
78095a65560Sthorpej 		strncpy(trtcm_add.iface.cdnr_ifname,
78195a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
78295a65560Sthorpej 		trtcm_add.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile;
78395a65560Sthorpej 		trtcm_add.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile;
78495a65560Sthorpej 		trtcm_add.green_action = cdnrinfo->tce_un.trtcm.green_action;
78595a65560Sthorpej 		trtcm_add.yellow_action = cdnrinfo->tce_un.trtcm.yellow_action;
78695a65560Sthorpej 		trtcm_add.red_action = cdnrinfo->tce_un.trtcm.red_action;
78795a65560Sthorpej 		trtcm_add.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
78895a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_ADD_TCM, &trtcm_add) < 0) {
78995a65560Sthorpej 			clinfo->handle = CDNR_NULL_HANDLE;
79095a65560Sthorpej 			return (QOPERR_SYSCALL);
79195a65560Sthorpej 		}
79295a65560Sthorpej 		clinfo->handle = trtcm_add.cdnr_handle;
79395a65560Sthorpej 		break;
79495a65560Sthorpej 
79595a65560Sthorpej 	case TCETYPE_TSWTCM:
79695a65560Sthorpej 		memset(&tswtcm_add, 0, sizeof(tswtcm_add));
79795a65560Sthorpej 		strncpy(tswtcm_add.iface.cdnr_ifname,
79895a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
79995a65560Sthorpej 		tswtcm_add.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
80095a65560Sthorpej 		tswtcm_add.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
80195a65560Sthorpej 		tswtcm_add.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
80295a65560Sthorpej 		tswtcm_add.green_action = cdnrinfo->tce_un.tswtcm.green_action;
80395a65560Sthorpej 		tswtcm_add.yellow_action = cdnrinfo->tce_un.tswtcm.yellow_action;
80495a65560Sthorpej 		tswtcm_add.red_action = cdnrinfo->tce_un.tswtcm.red_action;
80595a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_ADD_TSW, &tswtcm_add) < 0) {
80695a65560Sthorpej 			clinfo->handle = CDNR_NULL_HANDLE;
80795a65560Sthorpej 			return (QOPERR_SYSCALL);
80895a65560Sthorpej 		}
80995a65560Sthorpej 		clinfo->handle = tswtcm_add.cdnr_handle;
81095a65560Sthorpej 		break;
81195a65560Sthorpej 
81295a65560Sthorpej 	default:
81395a65560Sthorpej 		return (QOPERR_CLASS_INVAL);
81495a65560Sthorpej 	}
81595a65560Sthorpej 	return (0);
81695a65560Sthorpej }
81795a65560Sthorpej 
81895a65560Sthorpej static int
cdnr_modify_class(struct classinfo * clinfo,void * arg)81995a65560Sthorpej cdnr_modify_class(struct classinfo *clinfo, void *arg)
82095a65560Sthorpej {
82195a65560Sthorpej 	struct cdnr_modify_tbmeter tbmeter_modify;
82295a65560Sthorpej 	struct cdnr_modify_trtcm   trtcm_modify;
82395a65560Sthorpej 	struct cdnr_modify_tswtcm  tswtcm_modify;
82495a65560Sthorpej 	struct cdnrinfo *cdnrinfo;
82595a65560Sthorpej 
82695a65560Sthorpej 	cdnrinfo = clinfo->private;
82795a65560Sthorpej 
82895a65560Sthorpej 	switch (cdnrinfo->tce_type) {
82995a65560Sthorpej 	case TCETYPE_TBMETER:
83095a65560Sthorpej 		memset(&tbmeter_modify, 0, sizeof(tbmeter_modify));
83195a65560Sthorpej 		strncpy(tbmeter_modify.iface.cdnr_ifname,
83295a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
83395a65560Sthorpej 		tbmeter_modify.cdnr_handle = clinfo->handle;
83495a65560Sthorpej 		tbmeter_modify.profile = cdnrinfo->tce_un.tbmeter.profile;
83595a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_MOD_TBM, &tbmeter_modify) < 0)
83695a65560Sthorpej 			return (QOPERR_SYSCALL);
83795a65560Sthorpej 		break;
83895a65560Sthorpej 
83995a65560Sthorpej 	case TCETYPE_TRTCM:
84095a65560Sthorpej 		memset(&trtcm_modify, 0, sizeof(trtcm_modify));
84195a65560Sthorpej 		strncpy(trtcm_modify.iface.cdnr_ifname,
84295a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
84395a65560Sthorpej 		trtcm_modify.cdnr_handle = clinfo->handle;
84495a65560Sthorpej 		trtcm_modify.cmtd_profile =
84595a65560Sthorpej 			cdnrinfo->tce_un.trtcm.cmtd_profile;
84695a65560Sthorpej 		trtcm_modify.peak_profile =
84795a65560Sthorpej 			cdnrinfo->tce_un.trtcm.peak_profile;
84895a65560Sthorpej 		trtcm_modify.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
84995a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_MOD_TCM, &trtcm_modify) < 0)
85095a65560Sthorpej 			return (QOPERR_SYSCALL);
85195a65560Sthorpej 		break;
85295a65560Sthorpej 
85395a65560Sthorpej 	case TCETYPE_TSWTCM:
85495a65560Sthorpej 		memset(&tswtcm_modify, 0, sizeof(tswtcm_modify));
85595a65560Sthorpej 		strncpy(tswtcm_modify.iface.cdnr_ifname,
85695a65560Sthorpej 			clinfo->ifinfo->ifname+1, IFNAMSIZ);
85795a65560Sthorpej 		tswtcm_modify.cdnr_handle = clinfo->handle;
85895a65560Sthorpej 		tswtcm_modify.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
85995a65560Sthorpej 		tswtcm_modify.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
86095a65560Sthorpej 		tswtcm_modify.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
86195a65560Sthorpej 		if (ioctl(cdnr_fd, CDNR_MOD_TSW, &tswtcm_modify) < 0)
86295a65560Sthorpej 			return (QOPERR_SYSCALL);
86395a65560Sthorpej 		break;
86495a65560Sthorpej 
86595a65560Sthorpej 	default:
86695a65560Sthorpej 		return (QOPERR_CLASS_INVAL);
86795a65560Sthorpej 	}
86895a65560Sthorpej 	return (0);
86995a65560Sthorpej }
87095a65560Sthorpej 
87195a65560Sthorpej static int
cdnr_delete_class(struct classinfo * clinfo)87295a65560Sthorpej cdnr_delete_class(struct classinfo *clinfo)
87395a65560Sthorpej {
87495a65560Sthorpej 	struct cdnr_delete_element element_delete;
87595a65560Sthorpej 
87695a65560Sthorpej 	if (clinfo->handle == CDNR_NULL_HANDLE)
87795a65560Sthorpej 		return (0);
87895a65560Sthorpej 
87995a65560Sthorpej 	memset(&element_delete, 0, sizeof(element_delete));
88095a65560Sthorpej 	strncpy(element_delete.iface.cdnr_ifname, clinfo->ifinfo->ifname+1,
88195a65560Sthorpej 		IFNAMSIZ);
88295a65560Sthorpej 	element_delete.cdnr_handle = clinfo->handle;
88395a65560Sthorpej 
88495a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_DEL_ELEM, &element_delete) < 0)
88595a65560Sthorpej 		return (QOPERR_SYSCALL);
88695a65560Sthorpej 	return (0);
88795a65560Sthorpej }
88895a65560Sthorpej 
88995a65560Sthorpej static int
cdnr_add_filter(struct fltrinfo * fltrinfo)89095a65560Sthorpej cdnr_add_filter(struct fltrinfo *fltrinfo)
89195a65560Sthorpej {
89295a65560Sthorpej 	struct cdnr_add_filter fltr_add;
89395a65560Sthorpej 
89495a65560Sthorpej 	memset(&fltr_add, 0, sizeof(fltr_add));
89595a65560Sthorpej 	strncpy(fltr_add.iface.cdnr_ifname,
89695a65560Sthorpej 		fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
89795a65560Sthorpej 	fltr_add.cdnr_handle = fltrinfo->clinfo->handle;
89895a65560Sthorpej 	fltr_add.filter = fltrinfo->fltr;
89995a65560Sthorpej 
90095a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_ADD_FILTER, &fltr_add) < 0)
90195a65560Sthorpej 		return (QOPERR_SYSCALL);
90295a65560Sthorpej 	fltrinfo->handle = fltr_add.filter_handle;
90395a65560Sthorpej 	return (0);
90495a65560Sthorpej }
90595a65560Sthorpej 
90695a65560Sthorpej static int
cdnr_delete_filter(struct fltrinfo * fltrinfo)90795a65560Sthorpej cdnr_delete_filter(struct fltrinfo *fltrinfo)
90895a65560Sthorpej {
90995a65560Sthorpej 	struct cdnr_delete_filter fltr_del;
91095a65560Sthorpej 
91195a65560Sthorpej 	memset(&fltr_del, 0, sizeof(fltr_del));
91295a65560Sthorpej 	strncpy(fltr_del.iface.cdnr_ifname,
91395a65560Sthorpej 		fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
91495a65560Sthorpej 	fltr_del.filter_handle = fltrinfo->handle;
91595a65560Sthorpej 
91695a65560Sthorpej 	if (ioctl(cdnr_fd, CDNR_DEL_FILTER, &fltr_del) < 0)
91795a65560Sthorpej 		return (QOPERR_SYSCALL);
91895a65560Sthorpej 	return (0);
91995a65560Sthorpej }
92095a65560Sthorpej 
92195a65560Sthorpej 
92295a65560Sthorpej static int
verify_tbprofile(struct tb_profile * profile,const char * cdnr_name)92395a65560Sthorpej verify_tbprofile(struct tb_profile *profile, const char *cdnr_name)
92495a65560Sthorpej {
92595a65560Sthorpej 	if (profile->depth < 1500) {
92695a65560Sthorpej 		LOG(LOG_WARNING, 0,
927*d5e1f166Sitojun 		    "warning: token bucket depth for %s is too small (%d)",
92895a65560Sthorpej 		    cdnr_name, profile->depth);
92995a65560Sthorpej 		return (-1);
93095a65560Sthorpej 	}
93195a65560Sthorpej 	return (0);
93295a65560Sthorpej }
93395a65560Sthorpej 
934