Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / altq / libaltq / qop_cdnr.c
blobd0e9cd240a19d13f694d4e9cfe19cd3443d67068
1 /* $NetBSD: qop_cdnr.c,v 1.3 2001/08/16 07:48:13 itojun Exp $ */
2 /* $KAME: qop_cdnr.c,v 1.9 2001/08/16 10:39:14 kjc Exp $ */
3 /*
4 * Copyright (C) 1999-2000
5 * Sony Computer Science Laboratories, Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/sockio.h>
32 #include <sys/ioctl.h>
33 #include <sys/fcntl.h>
34 #include <net/if.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stddef.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <errno.h>
45 #include <syslog.h>
46 #include <netdb.h>
48 #include <altq/altq.h>
49 #include <altq/altq_cdnr.h>
50 #include "altq_qop.h"
51 #include "qop_cdnr.h"
53 * diffserve traffic conditioner support
55 * we use the existing qop interface to support conditioner.
58 static struct ifinfo *cdnr_ifname2ifinfo(const char *);
59 static int cdnr_attach(struct ifinfo *);
60 static int cdnr_detach(struct ifinfo *);
61 static int cdnr_enable(struct ifinfo *);
62 static int cdnr_disable(struct ifinfo *);
63 static int cdnr_add_class(struct classinfo *);
64 static int cdnr_modify_class(struct classinfo *, void *);
65 static int cdnr_delete_class(struct classinfo *);
66 static int cdnr_add_filter(struct fltrinfo *);
67 static int cdnr_delete_filter(struct fltrinfo *);
68 static int verify_tbprofile(struct tb_profile *, const char *);
70 #define CDNR_DEVICE "/dev/altq/cdnr"
72 static int cdnr_fd = -1;
73 static int cdnr_refcount = 0;
75 static struct qdisc_ops cdnr_qdisc = {
76 ALTQT_CDNR,
77 "cdnr",
78 cdnr_attach,
79 cdnr_detach,
80 NULL, /* clear */
81 cdnr_enable,
82 cdnr_disable,
83 cdnr_add_class,
84 cdnr_modify_class,
85 cdnr_delete_class,
86 cdnr_add_filter,
87 cdnr_delete_filter,
90 u_long
91 cdnr_name2handle(const char *ifname, const char *cdnr_name)
93 struct ifinfo *ifinfo;
94 struct classinfo *clinfo;
96 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
97 return (CDNR_NULL_HANDLE);
99 if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
100 return (CDNR_NULL_HANDLE);
102 return (clinfo->handle);
105 static struct ifinfo *
106 cdnr_ifname2ifinfo(const char *ifname)
108 struct ifinfo *ifinfo;
109 char input_ifname[64];
112 * search for an existing input interface
114 if ((ifinfo = input_ifname2ifinfo(ifname)) != NULL)
115 return (ifinfo);
118 * if there is a corresponding output interface,
119 * create an input interface by prepending "_" to
120 * its name.
122 if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
123 return (NULL);
125 input_ifname[0] = '_';
126 strlcpy(input_ifname+1, ifname, sizeof(input_ifname)-1);
127 if (qop_add_if(&ifinfo, input_ifname, 0, &cdnr_qdisc, NULL) != 0) {
128 LOG(LOG_ERR, errno,
129 "cdnr_ifname2ifinfo: can't add a input interface %s",
130 ifname);
131 return (NULL);
133 return (ifinfo);
137 qcmd_cdnr_add_element(struct tc_action *rp, const char *ifname,
138 const char *cdnr_name, struct tc_action *action)
140 struct ifinfo *ifinfo;
141 struct classinfo *clinfo;
142 int error;
144 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
145 return (QOPERR_BADIF);
147 if ((error = qop_cdnr_add_element(&clinfo, cdnr_name, ifinfo,
148 action)) != 0) {
149 LOG(LOG_ERR, errno, "%s: add element failed!",
150 qoperror(error));
151 return (error);
154 if (rp != NULL) {
155 rp->tca_code = TCACODE_HANDLE;
156 rp->tca_handle = clinfo->handle;
158 return (0);
162 qcmd_cdnr_add_tbmeter(struct tc_action *rp, const char *ifname,
163 const char *cdnr_name,
164 struct tb_profile *profile,
165 struct tc_action *in_action,
166 struct tc_action *out_action)
168 struct ifinfo *ifinfo;
169 struct classinfo *clinfo;
170 int error;
172 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
173 return (QOPERR_BADIF);
175 verify_tbprofile(profile, cdnr_name);
177 if ((error = qop_cdnr_add_tbmeter(&clinfo, cdnr_name, ifinfo,
178 profile, in_action, out_action)) != 0) {
179 LOG(LOG_ERR, errno, "%s: add tbmeter failed!",
180 qoperror(error));
181 return (error);
184 if (rp != NULL) {
185 rp->tca_code = TCACODE_HANDLE;
186 rp->tca_handle = clinfo->handle;
188 return (0);
192 qcmd_cdnr_add_trtcm(struct tc_action *rp, const char *ifname,
193 const char *cdnr_name,
194 struct tb_profile *cmtd_profile,
195 struct tb_profile *peak_profile,
196 struct tc_action *green_action,
197 struct tc_action *yellow_action,
198 struct tc_action *red_action, int coloraware)
200 struct ifinfo *ifinfo;
201 struct classinfo *clinfo;
202 int error;
204 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
205 return (QOPERR_BADIF);
207 verify_tbprofile(cmtd_profile, cdnr_name);
208 verify_tbprofile(peak_profile, cdnr_name);
210 if ((error = qop_cdnr_add_trtcm(&clinfo, cdnr_name, ifinfo,
211 cmtd_profile, peak_profile,
212 green_action, yellow_action, red_action,
213 coloraware)) != 0) {
214 LOG(LOG_ERR, errno, "%s: add trtcm failed!",
215 qoperror(error));
216 return (error);
219 if (rp != NULL) {
220 rp->tca_code = TCACODE_HANDLE;
221 rp->tca_handle = clinfo->handle;
223 return (0);
227 qcmd_cdnr_add_tswtcm(struct tc_action *rp, const char *ifname,
228 const char *cdnr_name, const u_int32_t cmtd_rate,
229 const u_int32_t peak_rate, const u_int32_t avg_interval,
230 struct tc_action *green_action,
231 struct tc_action *yellow_action,
232 struct tc_action *red_action)
234 struct ifinfo *ifinfo;
235 struct classinfo *clinfo;
236 int error;
238 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
239 return (QOPERR_BADIF);
241 if (cmtd_rate > peak_rate) {
242 LOG(LOG_ERR, 0,
243 "add tswtcm: cmtd_rate larger than peak_rate!");
244 return (QOPERR_INVAL);
247 if ((error = qop_cdnr_add_tswtcm(&clinfo, cdnr_name, ifinfo,
248 cmtd_rate, peak_rate, avg_interval,
249 green_action, yellow_action,
250 red_action)) != 0) {
251 LOG(LOG_ERR, errno, "%s: add tswtcm failed!",
252 qoperror(error));
253 return (error);
256 if (rp != NULL) {
257 rp->tca_code = TCACODE_HANDLE;
258 rp->tca_handle = clinfo->handle;
260 return (0);
264 qcmd_cdnr_delete(const char *ifname, const char *cdnr_name)
266 struct ifinfo *ifinfo;
267 struct classinfo *clinfo;
269 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL)
270 return (QOPERR_BADIF);
272 if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL)
273 return (QOPERR_BADCLASS);
275 return qop_delete_cdnr(clinfo);
279 * class operations:
280 * class structure is used to hold conditioners.
281 * XXX
282 * conditioners has dependencies in the reverse order; parent nodes
283 * refere to child nodes, and thus, a child is created first and
284 * parents should be removed first.
285 * qop_add_cdnr() and qop_delete_cdnr() are wrapper functions
286 * of qop_add_class() and qop_delete_class(), and takes care
287 * of dependencies.
288 * 1. when adding a conditioner, it is created as a child of a
289 * dummy root class. then, the child conditioners are made
290 * as its children.
291 * 2. when deleting a conditioner, its child conditioners are made
292 * as children of the dummy root class. then, the conditioner
293 * is deleted.
297 qop_add_cdnr(struct classinfo **rp, const char *cdnr_name,
298 struct ifinfo *ifinfo, struct classinfo **childlist,
299 void *cdnr_private)
301 struct classinfo *clinfo, *root, *cl, *prev;
302 int error;
305 * if there is no root cdnr, create one.
307 if ((root = get_rootclass(ifinfo)) == NULL) {
308 if ((error = qop_add_class(&root, "cdnr_root",
309 ifinfo, NULL, NULL)) != 0) {
310 LOG(LOG_ERR, errno,
311 "cdnr: %s: can't create dummy root cdnr on %s!",
312 qoperror(error), ifinfo->ifname);
313 return (QOPERR_CLASS);
318 * create a class as a child of a root class.
320 if ((error = qop_add_class(&clinfo, cdnr_name,
321 ifinfo, root, cdnr_private)) != 0)
322 return (error);
324 * move child nodes
326 for (cl = *childlist; cl != NULL; cl = *++childlist) {
327 if (cl->parent != root) {
329 * this conditioner already has a non-root parent.
330 * we can't track down a multi-parent node by a
331 * tree structure; leave it as it is.
332 * (we need a mechanism similar to a symbolic link
333 * in a file system)
335 continue;
337 /* remove this child from the root */
338 if (root->child == cl)
339 root->child = cl->sibling;
340 else for (prev = root->child;
341 prev->sibling != NULL; prev = prev->sibling)
342 if (prev->sibling == cl) {
343 prev->sibling = cl->sibling;
344 break;
347 /* add as a child */
348 cl->sibling = clinfo->child;
349 clinfo->child = cl;
350 cl->parent = clinfo;
353 if (rp != NULL)
354 *rp = clinfo;
355 return (0);
359 qop_delete_cdnr(struct classinfo *clinfo)
361 struct classinfo *cl, *root;
362 int error;
364 if ((root = get_rootclass(clinfo->ifinfo)) == NULL) {
365 LOG(LOG_ERR, 0, "qop_delete_cdnr: no root cdnr!");
366 return (QOPERR_CLASS);
369 if (clinfo->parent != root)
370 return (QOPERR_CLASS_PERM);
372 if ((cl = clinfo->child) != NULL) {
373 /* change child's parent to root, find the last child */
374 while (cl->sibling != NULL) {
375 cl->parent = root;
376 cl = cl->sibling;
378 cl->parent = root;
380 /* move children to siblings */
381 cl->sibling = clinfo->sibling;
382 clinfo->sibling = cl;
383 clinfo->child = NULL;
386 error = qop_delete_class(clinfo);
388 if (error) {
389 /* ick! restore the class tree */
390 if (cl != NULL) {
391 clinfo->child = clinfo->sibling;
392 clinfo->sibling = cl->sibling;
393 cl->sibling = NULL;
394 /* restore parent field */
395 for (cl = clinfo->child; cl != NULL; cl = cl->sibling)
396 cl->parent = clinfo;
399 return (error);
402 int
403 qop_cdnr_add_element(struct classinfo **rp, const char *cdnr_name,
404 struct ifinfo *ifinfo, struct tc_action *action)
406 struct classinfo *clinfo, *clist[2];
407 struct cdnrinfo *cdnrinfo = NULL;
408 int error;
410 if (action->tca_code == TCACODE_HANDLE) {
411 clinfo = clhandle2clinfo(ifinfo, action->tca_handle);
412 if (clinfo == NULL)
413 return (QOPERR_BADCLASS);
414 clist[0] = clinfo;
415 clist[1] = NULL;
416 #if 1
418 * if the conditioner referred to doesn't have a name,
419 * this is called just to add a name to it.
420 * we can simply add the name to the existing conditioner
421 * and return it.
423 if (cdnr_name != NULL &&
424 strcmp(clinfo->clname, "(null)") == 0) {
425 free(clinfo->clname);
426 clinfo->clname = strdup(cdnr_name);
427 if (rp != NULL)
428 *rp = clinfo;
429 return (0);
431 #endif
432 } else
433 clist[0] = NULL;
435 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
436 return (QOPERR_NOMEM);
438 cdnrinfo->tce_type = TCETYPE_ELEMENT;
439 cdnrinfo->tce_un.element.action = *action;
441 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
442 cdnrinfo)) != 0)
443 goto err_ret;
445 if (rp != NULL)
446 *rp = clinfo;
447 return (0);
449 err_ret:
450 if (cdnrinfo != NULL)
451 free(cdnrinfo);
452 return (error);
455 int
456 qop_cdnr_add_tbmeter(struct classinfo **rp, const char *cdnr_name,
457 struct ifinfo *ifinfo,
458 struct tb_profile *profile,
459 struct tc_action *in_action,
460 struct tc_action *out_action)
462 struct classinfo *clinfo, *clist[3];
463 struct cdnrinfo *cdnrinfo = NULL;
464 int n, error;
466 n = 0;
467 if (in_action->tca_code == TCACODE_HANDLE) {
468 clist[n] = clhandle2clinfo(ifinfo, in_action->tca_handle);
469 if (clist[n] == NULL)
470 return (QOPERR_BADCLASS);
471 n++;
473 if (out_action->tca_code == TCACODE_HANDLE) {
474 clist[n] = clhandle2clinfo(ifinfo, out_action->tca_handle);
475 if (clist[n] == NULL)
476 return (QOPERR_BADCLASS);
477 n++;
479 clist[n] = NULL;
481 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
482 return (QOPERR_NOMEM);
484 cdnrinfo->tce_type = TCETYPE_TBMETER;
485 cdnrinfo->tce_un.tbmeter.profile = *profile;
486 cdnrinfo->tce_un.tbmeter.in_action = *in_action;
487 cdnrinfo->tce_un.tbmeter.out_action = *out_action;
489 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
490 cdnrinfo)) != 0)
491 goto err_ret;
493 if (rp != NULL)
494 *rp = clinfo;
495 return (0);
497 err_ret:
498 if (cdnrinfo != NULL)
499 free(cdnrinfo);
500 return (error);
503 int
504 qop_cdnr_modify_tbmeter(struct classinfo *clinfo, struct tb_profile *profile)
506 struct cdnrinfo *cdnrinfo = clinfo->private;
508 if (cdnrinfo->tce_type != TCETYPE_TBMETER)
509 return (QOPERR_CLASS_INVAL);
510 cdnrinfo->tce_un.tbmeter.profile = *profile;
512 return qop_modify_class(clinfo, NULL);
515 int
516 qop_cdnr_add_trtcm(struct classinfo **rp, const char *cdnr_name,
517 struct ifinfo *ifinfo,
518 struct tb_profile *cmtd_profile,
519 struct tb_profile *peak_profile,
520 struct tc_action *green_action,
521 struct tc_action *yellow_action,
522 struct tc_action *red_action, int coloraware)
524 struct classinfo *clinfo, *clist[4];
525 struct cdnrinfo *cdnrinfo = NULL;
526 int n, error;
528 n = 0;
529 if (green_action->tca_code == TCACODE_HANDLE) {
530 clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
531 if (clist[n] == NULL)
532 return (QOPERR_BADCLASS);
533 n++;
535 if (yellow_action->tca_code == TCACODE_HANDLE) {
536 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
537 if (clist[n] == NULL)
538 return (QOPERR_BADCLASS);
539 n++;
541 if (red_action->tca_code == TCACODE_HANDLE) {
542 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
543 if (clist[n] == NULL)
544 return (QOPERR_BADCLASS);
545 n++;
547 clist[n] = NULL;
549 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
550 return (QOPERR_NOMEM);
552 cdnrinfo->tce_type = TCETYPE_TRTCM;
553 cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
554 cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
555 cdnrinfo->tce_un.trtcm.green_action = *green_action;
556 cdnrinfo->tce_un.trtcm.yellow_action = *yellow_action;
557 cdnrinfo->tce_un.trtcm.red_action = *red_action;
558 cdnrinfo->tce_un.trtcm.coloraware = coloraware;
560 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
561 cdnrinfo)) != 0)
562 goto err_ret;
564 if (rp != NULL)
565 *rp = clinfo;
566 return (0);
568 err_ret:
569 if (cdnrinfo != NULL)
570 free(cdnrinfo);
571 return (error);
574 int
575 qop_cdnr_modify_trtcm(struct classinfo *clinfo,
576 struct tb_profile *cmtd_profile,
577 struct tb_profile *peak_profile, int coloraware)
579 struct cdnrinfo *cdnrinfo = clinfo->private;
581 if (cdnrinfo->tce_type != TCETYPE_TRTCM)
582 return (QOPERR_CLASS_INVAL);
583 cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile;
584 cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile;
585 cdnrinfo->tce_un.trtcm.coloraware = coloraware;
587 return qop_modify_class(clinfo, NULL);
590 int
591 qop_cdnr_add_tswtcm(struct classinfo **rp, const char *cdnr_name,
592 struct ifinfo *ifinfo, const u_int32_t cmtd_rate,
593 const u_int32_t peak_rate, const u_int32_t avg_interval,
594 struct tc_action *green_action,
595 struct tc_action *yellow_action,
596 struct tc_action *red_action)
598 struct classinfo *clinfo, *clist[4];
599 struct cdnrinfo *cdnrinfo = NULL;
600 int n, error;
602 n = 0;
603 if (green_action->tca_code == TCACODE_HANDLE) {
604 clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle);
605 if (clist[n] == NULL)
606 return (QOPERR_BADCLASS);
607 n++;
609 if (yellow_action->tca_code == TCACODE_HANDLE) {
610 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
611 if (clist[n] == NULL)
612 return (QOPERR_BADCLASS);
613 n++;
615 if (red_action->tca_code == TCACODE_HANDLE) {
616 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle);
617 if (clist[n] == NULL)
618 return (QOPERR_BADCLASS);
619 n++;
621 clist[n] = NULL;
623 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL)
624 return (QOPERR_NOMEM);
626 cdnrinfo->tce_type = TCETYPE_TSWTCM;
627 cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
628 cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
629 cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
630 cdnrinfo->tce_un.tswtcm.green_action = *green_action;
631 cdnrinfo->tce_un.tswtcm.yellow_action = *yellow_action;
632 cdnrinfo->tce_un.tswtcm.red_action = *red_action;
634 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist,
635 cdnrinfo)) != 0)
636 goto err_ret;
638 if (rp != NULL)
639 *rp = clinfo;
640 return (0);
642 err_ret:
643 if (cdnrinfo != NULL)
644 free(cdnrinfo);
645 return (error);
648 int
649 qop_cdnr_modify_tswtcm(struct classinfo *clinfo, const u_int32_t cmtd_rate,
650 const u_int32_t peak_rate, const u_int32_t avg_interval)
652 struct cdnrinfo *cdnrinfo = clinfo->private;
654 if (cdnrinfo->tce_type != TCETYPE_TSWTCM)
655 return (QOPERR_CLASS_INVAL);
656 cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate;
657 cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate;
658 cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval;
660 return qop_modify_class(clinfo, NULL);
664 * system call interfaces for qdisc_ops
666 static int
667 cdnr_attach(struct ifinfo *ifinfo)
669 struct cdnr_interface iface;
671 if (cdnr_fd < 0 &&
672 (cdnr_fd = open(CDNR_DEVICE, O_RDWR)) < 0 &&
673 (cdnr_fd = open_module(CDNR_DEVICE, O_RDWR)) < 0) {
674 LOG(LOG_ERR, errno, "CDNR open");
675 return (QOPERR_SYSCALL);
678 cdnr_refcount++;
679 memset(&iface, 0, sizeof(iface));
680 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
682 if (ioctl(cdnr_fd, CDNR_IF_ATTACH, &iface) < 0)
683 return (QOPERR_SYSCALL);
684 #if 1
685 LOG(LOG_INFO, 0, "conditioner attached to %s", iface.cdnr_ifname);
686 #endif
687 return (0);
690 static int
691 cdnr_detach(struct ifinfo *ifinfo)
693 struct cdnr_interface iface;
695 memset(&iface, 0, sizeof(iface));
696 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
698 if (ioctl(cdnr_fd, CDNR_IF_DETACH, &iface) < 0)
699 return (QOPERR_SYSCALL);
701 if (--cdnr_refcount == 0) {
702 close(cdnr_fd);
703 cdnr_fd = -1;
705 return (0);
708 static int
709 cdnr_enable(struct ifinfo *ifinfo)
711 struct cdnr_interface iface;
713 memset(&iface, 0, sizeof(iface));
714 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
716 if (ioctl(cdnr_fd, CDNR_ENABLE, &iface) < 0)
717 return (QOPERR_SYSCALL);
718 return (0);
721 static int
722 cdnr_disable(struct ifinfo *ifinfo)
724 struct cdnr_interface iface;
726 memset(&iface, 0, sizeof(iface));
727 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ);
729 if (ioctl(cdnr_fd, CDNR_DISABLE, &iface) < 0)
730 return (QOPERR_SYSCALL);
731 return (0);
734 static int
735 cdnr_add_class(struct classinfo *clinfo)
737 struct cdnr_add_element element_add;
738 struct cdnr_add_tbmeter tbmeter_add;
739 struct cdnr_add_trtcm trtcm_add;
740 struct cdnr_add_tswtcm tswtcm_add;
741 struct cdnrinfo *cdnrinfo;
743 cdnrinfo = clinfo->private;
745 /* root class is a dummy class */
746 if (clinfo->parent == NULL) {
747 clinfo->handle = 0;
748 return (0);
751 switch (cdnrinfo->tce_type) {
752 case TCETYPE_ELEMENT:
753 memset(&element_add, 0, sizeof(element_add));
754 strncpy(element_add.iface.cdnr_ifname,
755 clinfo->ifinfo->ifname+1, IFNAMSIZ);
756 element_add.action = cdnrinfo->tce_un.element.action;
757 if (ioctl(cdnr_fd, CDNR_ADD_ELEM, &element_add) < 0) {
758 clinfo->handle = CDNR_NULL_HANDLE;
759 return (QOPERR_SYSCALL);
761 clinfo->handle = element_add.cdnr_handle;
762 break;
764 case TCETYPE_TBMETER:
765 memset(&tbmeter_add, 0, sizeof(tbmeter_add));
766 strncpy(tbmeter_add.iface.cdnr_ifname,
767 clinfo->ifinfo->ifname+1, IFNAMSIZ);
768 tbmeter_add.profile = cdnrinfo->tce_un.tbmeter.profile;
769 tbmeter_add.in_action = cdnrinfo->tce_un.tbmeter.in_action;
770 tbmeter_add.out_action = cdnrinfo->tce_un.tbmeter.out_action;
771 if (ioctl(cdnr_fd, CDNR_ADD_TBM, &tbmeter_add) < 0) {
772 clinfo->handle = CDNR_NULL_HANDLE;
773 return (QOPERR_SYSCALL);
775 clinfo->handle = tbmeter_add.cdnr_handle;
776 break;
778 case TCETYPE_TRTCM:
779 memset(&trtcm_add, 0, sizeof(trtcm_add));
780 strncpy(trtcm_add.iface.cdnr_ifname,
781 clinfo->ifinfo->ifname+1, IFNAMSIZ);
782 trtcm_add.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile;
783 trtcm_add.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile;
784 trtcm_add.green_action = cdnrinfo->tce_un.trtcm.green_action;
785 trtcm_add.yellow_action = cdnrinfo->tce_un.trtcm.yellow_action;
786 trtcm_add.red_action = cdnrinfo->tce_un.trtcm.red_action;
787 trtcm_add.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
788 if (ioctl(cdnr_fd, CDNR_ADD_TCM, &trtcm_add) < 0) {
789 clinfo->handle = CDNR_NULL_HANDLE;
790 return (QOPERR_SYSCALL);
792 clinfo->handle = trtcm_add.cdnr_handle;
793 break;
795 case TCETYPE_TSWTCM:
796 memset(&tswtcm_add, 0, sizeof(tswtcm_add));
797 strncpy(tswtcm_add.iface.cdnr_ifname,
798 clinfo->ifinfo->ifname+1, IFNAMSIZ);
799 tswtcm_add.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
800 tswtcm_add.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
801 tswtcm_add.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
802 tswtcm_add.green_action = cdnrinfo->tce_un.tswtcm.green_action;
803 tswtcm_add.yellow_action = cdnrinfo->tce_un.tswtcm.yellow_action;
804 tswtcm_add.red_action = cdnrinfo->tce_un.tswtcm.red_action;
805 if (ioctl(cdnr_fd, CDNR_ADD_TSW, &tswtcm_add) < 0) {
806 clinfo->handle = CDNR_NULL_HANDLE;
807 return (QOPERR_SYSCALL);
809 clinfo->handle = tswtcm_add.cdnr_handle;
810 break;
812 default:
813 return (QOPERR_CLASS_INVAL);
815 return (0);
818 static int
819 cdnr_modify_class(struct classinfo *clinfo, void *arg)
821 struct cdnr_modify_tbmeter tbmeter_modify;
822 struct cdnr_modify_trtcm trtcm_modify;
823 struct cdnr_modify_tswtcm tswtcm_modify;
824 struct cdnrinfo *cdnrinfo;
826 cdnrinfo = clinfo->private;
828 switch (cdnrinfo->tce_type) {
829 case TCETYPE_TBMETER:
830 memset(&tbmeter_modify, 0, sizeof(tbmeter_modify));
831 strncpy(tbmeter_modify.iface.cdnr_ifname,
832 clinfo->ifinfo->ifname+1, IFNAMSIZ);
833 tbmeter_modify.cdnr_handle = clinfo->handle;
834 tbmeter_modify.profile = cdnrinfo->tce_un.tbmeter.profile;
835 if (ioctl(cdnr_fd, CDNR_MOD_TBM, &tbmeter_modify) < 0)
836 return (QOPERR_SYSCALL);
837 break;
839 case TCETYPE_TRTCM:
840 memset(&trtcm_modify, 0, sizeof(trtcm_modify));
841 strncpy(trtcm_modify.iface.cdnr_ifname,
842 clinfo->ifinfo->ifname+1, IFNAMSIZ);
843 trtcm_modify.cdnr_handle = clinfo->handle;
844 trtcm_modify.cmtd_profile =
845 cdnrinfo->tce_un.trtcm.cmtd_profile;
846 trtcm_modify.peak_profile =
847 cdnrinfo->tce_un.trtcm.peak_profile;
848 trtcm_modify.coloraware = cdnrinfo->tce_un.trtcm.coloraware;
849 if (ioctl(cdnr_fd, CDNR_MOD_TCM, &trtcm_modify) < 0)
850 return (QOPERR_SYSCALL);
851 break;
853 case TCETYPE_TSWTCM:
854 memset(&tswtcm_modify, 0, sizeof(tswtcm_modify));
855 strncpy(tswtcm_modify.iface.cdnr_ifname,
856 clinfo->ifinfo->ifname+1, IFNAMSIZ);
857 tswtcm_modify.cdnr_handle = clinfo->handle;
858 tswtcm_modify.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate;
859 tswtcm_modify.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate;
860 tswtcm_modify.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval;
861 if (ioctl(cdnr_fd, CDNR_MOD_TSW, &tswtcm_modify) < 0)
862 return (QOPERR_SYSCALL);
863 break;
865 default:
866 return (QOPERR_CLASS_INVAL);
868 return (0);
871 static int
872 cdnr_delete_class(struct classinfo *clinfo)
874 struct cdnr_delete_element element_delete;
876 if (clinfo->handle == CDNR_NULL_HANDLE)
877 return (0);
879 memset(&element_delete, 0, sizeof(element_delete));
880 strncpy(element_delete.iface.cdnr_ifname, clinfo->ifinfo->ifname+1,
881 IFNAMSIZ);
882 element_delete.cdnr_handle = clinfo->handle;
884 if (ioctl(cdnr_fd, CDNR_DEL_ELEM, &element_delete) < 0)
885 return (QOPERR_SYSCALL);
886 return (0);
889 static int
890 cdnr_add_filter(struct fltrinfo *fltrinfo)
892 struct cdnr_add_filter fltr_add;
894 memset(&fltr_add, 0, sizeof(fltr_add));
895 strncpy(fltr_add.iface.cdnr_ifname,
896 fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
897 fltr_add.cdnr_handle = fltrinfo->clinfo->handle;
898 fltr_add.filter = fltrinfo->fltr;
900 if (ioctl(cdnr_fd, CDNR_ADD_FILTER, &fltr_add) < 0)
901 return (QOPERR_SYSCALL);
902 fltrinfo->handle = fltr_add.filter_handle;
903 return (0);
906 static int
907 cdnr_delete_filter(struct fltrinfo *fltrinfo)
909 struct cdnr_delete_filter fltr_del;
911 memset(&fltr_del, 0, sizeof(fltr_del));
912 strncpy(fltr_del.iface.cdnr_ifname,
913 fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ);
914 fltr_del.filter_handle = fltrinfo->handle;
916 if (ioctl(cdnr_fd, CDNR_DEL_FILTER, &fltr_del) < 0)
917 return (QOPERR_SYSCALL);
918 return (0);
922 static int
923 verify_tbprofile(struct tb_profile *profile, const char *cdnr_name)
925 if (profile->depth < 1500) {
926 LOG(LOG_WARNING, 0,
927 "warning: token bucket depth for %s is too small (%d)",
928 cdnr_name, profile->depth);
929 return (-1);
931 return (0);