/* $NetBSD: qop_cdnr.c,v 1.4 2001/08/22 08:52:37 itojun Exp $ */ /* $KAME: qop_cdnr.c,v 1.9 2001/08/16 10:39:14 kjc Exp $ */ /* * Copyright (C) 1999-2000 * Sony Computer Science Laboratories, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "altq_qop.h" #include "qop_cdnr.h" /* * diffserve traffic conditioner support * * we use the existing qop interface to support conditioner. */ static struct ifinfo *cdnr_ifname2ifinfo(const char *); static int cdnr_attach(struct ifinfo *); static int cdnr_detach(struct ifinfo *); static int cdnr_enable(struct ifinfo *); static int cdnr_disable(struct ifinfo *); static int cdnr_add_class(struct classinfo *); static int cdnr_modify_class(struct classinfo *, void *); static int cdnr_delete_class(struct classinfo *); static int cdnr_add_filter(struct fltrinfo *); static int cdnr_delete_filter(struct fltrinfo *); static int verify_tbprofile(struct tb_profile *, const char *); #define CDNR_DEVICE "/dev/altq/cdnr" static int cdnr_fd = -1; static int cdnr_refcount = 0; static struct qdisc_ops cdnr_qdisc = { ALTQT_CDNR, "cdnr", cdnr_attach, cdnr_detach, NULL, /* clear */ cdnr_enable, cdnr_disable, cdnr_add_class, cdnr_modify_class, cdnr_delete_class, cdnr_add_filter, cdnr_delete_filter, }; u_long cdnr_name2handle(const char *ifname, const char *cdnr_name) { struct ifinfo *ifinfo; struct classinfo *clinfo; if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) return (CDNR_NULL_HANDLE); if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL) return (CDNR_NULL_HANDLE); return (clinfo->handle); } static struct ifinfo * cdnr_ifname2ifinfo(const char *ifname) { struct ifinfo *ifinfo; char input_ifname[64]; /* * search for an existing input interface */ if ((ifinfo = input_ifname2ifinfo(ifname)) != NULL) return (ifinfo); /* * if there is a corresponding output interface, * create an input interface by prepending "_" to * its name. */ if ((ifinfo = ifname2ifinfo(ifname)) == NULL) return (NULL); input_ifname[0] = '_'; strlcpy(input_ifname+1, ifname, sizeof(input_ifname)-1); if (qop_add_if(&ifinfo, input_ifname, 0, &cdnr_qdisc, NULL) != 0) { LOG(LOG_ERR, errno, "cdnr_ifname2ifinfo: can't add a input interface %s", ifname); return (NULL); } return (ifinfo); } int qcmd_cdnr_add_element(struct tc_action *rp, const char *ifname, const char *cdnr_name, struct tc_action *action) { struct ifinfo *ifinfo; struct classinfo *clinfo; int error; if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) return (QOPERR_BADIF); if ((error = qop_cdnr_add_element(&clinfo, cdnr_name, ifinfo, action)) != 0) { LOG(LOG_ERR, errno, "%s: add element failed!", qoperror(error)); return (error); } if (rp != NULL) { rp->tca_code = TCACODE_HANDLE; rp->tca_handle = clinfo->handle; } return (0); } 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) { struct ifinfo *ifinfo; struct classinfo *clinfo; int error; if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) return (QOPERR_BADIF); verify_tbprofile(profile, cdnr_name); if ((error = qop_cdnr_add_tbmeter(&clinfo, cdnr_name, ifinfo, profile, in_action, out_action)) != 0) { LOG(LOG_ERR, errno, "%s: add tbmeter failed!", qoperror(error)); return (error); } if (rp != NULL) { rp->tca_code = TCACODE_HANDLE; rp->tca_handle = clinfo->handle; } return (0); } 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) { struct ifinfo *ifinfo; struct classinfo *clinfo; int error; if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) return (QOPERR_BADIF); verify_tbprofile(cmtd_profile, cdnr_name); verify_tbprofile(peak_profile, cdnr_name); if ((error = qop_cdnr_add_trtcm(&clinfo, cdnr_name, ifinfo, cmtd_profile, peak_profile, green_action, yellow_action, red_action, coloraware)) != 0) { LOG(LOG_ERR, errno, "%s: add trtcm failed!", qoperror(error)); return (error); } if (rp != NULL) { rp->tca_code = TCACODE_HANDLE; rp->tca_handle = clinfo->handle; } return (0); } 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) { struct ifinfo *ifinfo; struct classinfo *clinfo; int error; if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) return (QOPERR_BADIF); if (cmtd_rate > peak_rate) { LOG(LOG_ERR, 0, "add tswtcm: cmtd_rate larger than peak_rate!"); return (QOPERR_INVAL); } if ((error = qop_cdnr_add_tswtcm(&clinfo, cdnr_name, ifinfo, cmtd_rate, peak_rate, avg_interval, green_action, yellow_action, red_action)) != 0) { LOG(LOG_ERR, errno, "%s: add tswtcm failed!", qoperror(error)); return (error); } if (rp != NULL) { rp->tca_code = TCACODE_HANDLE; rp->tca_handle = clinfo->handle; } return (0); } int qcmd_cdnr_delete(const char *ifname, const char *cdnr_name) { struct ifinfo *ifinfo; struct classinfo *clinfo; if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) return (QOPERR_BADIF); if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL) return (QOPERR_BADCLASS); return qop_delete_cdnr(clinfo); } /* * class operations: * class structure is used to hold conditioners. * XXX * conditioners has dependencies in the reverse order; parent nodes * refere to child nodes, and thus, a child is created first and * parents should be removed first. * qop_add_cdnr() and qop_delete_cdnr() are wrapper functions * of qop_add_class() and qop_delete_class(), and takes care * of dependencies. * 1. when adding a conditioner, it is created as a child of a * dummy root class. then, the child conditioners are made * as its children. * 2. when deleting a conditioner, its child conditioners are made * as children of the dummy root class. then, the conditioner * is deleted. */ int qop_add_cdnr(struct classinfo **rp, const char *cdnr_name, struct ifinfo *ifinfo, struct classinfo **childlist, void *cdnr_private) { struct classinfo *clinfo, *root, *cl, *prev; int error; /* * if there is no root cdnr, create one. */ if ((root = get_rootclass(ifinfo)) == NULL) { if ((error = qop_add_class(&root, "cdnr_root", ifinfo, NULL, NULL)) != 0) { LOG(LOG_ERR, errno, "cdnr: %s: can't create dummy root cdnr on %s!", qoperror(error), ifinfo->ifname); return (QOPERR_CLASS); } } /* * create a class as a child of a root class. */ if ((error = qop_add_class(&clinfo, cdnr_name, ifinfo, root, cdnr_private)) != 0) return (error); /* * move child nodes */ for (cl = *childlist; cl != NULL; cl = *++childlist) { if (cl->parent != root) { /* * this conditioner already has a non-root parent. * we can't track down a multi-parent node by a * tree structure; leave it as it is. * (we need a mechanism similar to a symbolic link * in a file system) */ continue; } /* remove this child from the root */ if (root->child == cl) root->child = cl->sibling; else for (prev = root->child; prev->sibling != NULL; prev = prev->sibling) if (prev->sibling == cl) { prev->sibling = cl->sibling; break; } /* add as a child */ cl->sibling = clinfo->child; clinfo->child = cl; cl->parent = clinfo; } if (rp != NULL) *rp = clinfo; return (0); } int qop_delete_cdnr(struct classinfo *clinfo) { struct classinfo *cl, *root; int error; if ((root = get_rootclass(clinfo->ifinfo)) == NULL) { LOG(LOG_ERR, 0, "qop_delete_cdnr: no root cdnr!"); return (QOPERR_CLASS); } if (clinfo->parent != root) return (QOPERR_CLASS_PERM); if ((cl = clinfo->child) != NULL) { /* change child's parent to root, find the last child */ while (cl->sibling != NULL) { cl->parent = root; cl = cl->sibling; } cl->parent = root; /* move children to siblings */ cl->sibling = clinfo->sibling; clinfo->sibling = cl; clinfo->child = NULL; } error = qop_delete_class(clinfo); if (error) { /* ick! restore the class tree */ if (cl != NULL) { clinfo->child = clinfo->sibling; clinfo->sibling = cl->sibling; cl->sibling = NULL; /* restore parent field */ for (cl = clinfo->child; cl != NULL; cl = cl->sibling) cl->parent = clinfo; } } return (error); } int qop_cdnr_add_element(struct classinfo **rp, const char *cdnr_name, struct ifinfo *ifinfo, struct tc_action *action) { struct classinfo *clinfo, *clist[2]; struct cdnrinfo *cdnrinfo = NULL; int error; if (action->tca_code == TCACODE_HANDLE) { clinfo = clhandle2clinfo(ifinfo, action->tca_handle); if (clinfo == NULL) return (QOPERR_BADCLASS); clist[0] = clinfo; clist[1] = NULL; #if 1 /* * if the conditioner referred to doesn't have a name, * this is called just to add a name to it. * we can simply add the name to the existing conditioner * and return it. */ if (cdnr_name != NULL && strcmp(clinfo->clname, "(null)") == 0) { free(clinfo->clname); clinfo->clname = strdup(cdnr_name); if (rp != NULL) *rp = clinfo; return (0); } #endif } else clist[0] = NULL; if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) return (QOPERR_NOMEM); cdnrinfo->tce_type = TCETYPE_ELEMENT; cdnrinfo->tce_un.element.action = *action; if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, cdnrinfo)) != 0) goto err_ret; if (rp != NULL) *rp = clinfo; return (0); err_ret: if (cdnrinfo != NULL) free(cdnrinfo); return (error); } 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) { struct classinfo *clinfo, *clist[3]; struct cdnrinfo *cdnrinfo = NULL; int n, error; n = 0; if (in_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, in_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } if (out_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, out_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } clist[n] = NULL; if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) return (QOPERR_NOMEM); cdnrinfo->tce_type = TCETYPE_TBMETER; cdnrinfo->tce_un.tbmeter.profile = *profile; cdnrinfo->tce_un.tbmeter.in_action = *in_action; cdnrinfo->tce_un.tbmeter.out_action = *out_action; if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, cdnrinfo)) != 0) goto err_ret; if (rp != NULL) *rp = clinfo; return (0); err_ret: if (cdnrinfo != NULL) free(cdnrinfo); return (error); } int qop_cdnr_modify_tbmeter(struct classinfo *clinfo, struct tb_profile *profile) { struct cdnrinfo *cdnrinfo = clinfo->private; if (cdnrinfo->tce_type != TCETYPE_TBMETER) return (QOPERR_CLASS_INVAL); cdnrinfo->tce_un.tbmeter.profile = *profile; return qop_modify_class(clinfo, NULL); } 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) { struct classinfo *clinfo, *clist[4]; struct cdnrinfo *cdnrinfo = NULL; int n, error; n = 0; if (green_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } if (yellow_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } if (red_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } clist[n] = NULL; if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) return (QOPERR_NOMEM); cdnrinfo->tce_type = TCETYPE_TRTCM; cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile; cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile; cdnrinfo->tce_un.trtcm.green_action = *green_action; cdnrinfo->tce_un.trtcm.yellow_action = *yellow_action; cdnrinfo->tce_un.trtcm.red_action = *red_action; cdnrinfo->tce_un.trtcm.coloraware = coloraware; if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, cdnrinfo)) != 0) goto err_ret; if (rp != NULL) *rp = clinfo; return (0); err_ret: if (cdnrinfo != NULL) free(cdnrinfo); return (error); } int qop_cdnr_modify_trtcm(struct classinfo *clinfo, struct tb_profile *cmtd_profile, struct tb_profile *peak_profile, int coloraware) { struct cdnrinfo *cdnrinfo = clinfo->private; if (cdnrinfo->tce_type != TCETYPE_TRTCM) return (QOPERR_CLASS_INVAL); cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile; cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile; cdnrinfo->tce_un.trtcm.coloraware = coloraware; return qop_modify_class(clinfo, NULL); } 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) { struct classinfo *clinfo, *clist[4]; struct cdnrinfo *cdnrinfo = NULL; int n, error; n = 0; if (green_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } if (yellow_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } if (red_action->tca_code == TCACODE_HANDLE) { clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); if (clist[n] == NULL) return (QOPERR_BADCLASS); n++; } clist[n] = NULL; if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) return (QOPERR_NOMEM); cdnrinfo->tce_type = TCETYPE_TSWTCM; cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate; cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate; cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval; cdnrinfo->tce_un.tswtcm.green_action = *green_action; cdnrinfo->tce_un.tswtcm.yellow_action = *yellow_action; cdnrinfo->tce_un.tswtcm.red_action = *red_action; if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, cdnrinfo)) != 0) goto err_ret; if (rp != NULL) *rp = clinfo; return (0); err_ret: if (cdnrinfo != NULL) free(cdnrinfo); return (error); } 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) { struct cdnrinfo *cdnrinfo = clinfo->private; if (cdnrinfo->tce_type != TCETYPE_TSWTCM) return (QOPERR_CLASS_INVAL); cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate; cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate; cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval; return qop_modify_class(clinfo, NULL); } /* * system call interfaces for qdisc_ops */ static int cdnr_attach(struct ifinfo *ifinfo) { struct cdnr_interface iface; if (cdnr_fd < 0 && (cdnr_fd = open(CDNR_DEVICE, O_RDWR)) < 0 && (cdnr_fd = open_module(CDNR_DEVICE, O_RDWR)) < 0) { LOG(LOG_ERR, errno, "CDNR open"); return (QOPERR_SYSCALL); } cdnr_refcount++; memset(&iface, 0, sizeof(iface)); strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); if (ioctl(cdnr_fd, CDNR_IF_ATTACH, &iface) < 0) return (QOPERR_SYSCALL); #if 1 LOG(LOG_INFO, 0, "conditioner attached to %s", iface.cdnr_ifname); #endif return (0); } static int cdnr_detach(struct ifinfo *ifinfo) { struct cdnr_interface iface; memset(&iface, 0, sizeof(iface)); strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); if (ioctl(cdnr_fd, CDNR_IF_DETACH, &iface) < 0) return (QOPERR_SYSCALL); if (--cdnr_refcount == 0) { close(cdnr_fd); cdnr_fd = -1; } return (0); } static int cdnr_enable(struct ifinfo *ifinfo) { struct cdnr_interface iface; memset(&iface, 0, sizeof(iface)); strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); if (ioctl(cdnr_fd, CDNR_ENABLE, &iface) < 0) return (QOPERR_SYSCALL); return (0); } static int cdnr_disable(struct ifinfo *ifinfo) { struct cdnr_interface iface; memset(&iface, 0, sizeof(iface)); strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); if (ioctl(cdnr_fd, CDNR_DISABLE, &iface) < 0) return (QOPERR_SYSCALL); return (0); } static int cdnr_add_class(struct classinfo *clinfo) { struct cdnr_add_element element_add; struct cdnr_add_tbmeter tbmeter_add; struct cdnr_add_trtcm trtcm_add; struct cdnr_add_tswtcm tswtcm_add; struct cdnrinfo *cdnrinfo; cdnrinfo = clinfo->private; /* root class is a dummy class */ if (clinfo->parent == NULL) { clinfo->handle = 0; return (0); } switch (cdnrinfo->tce_type) { case TCETYPE_ELEMENT: memset(&element_add, 0, sizeof(element_add)); strncpy(element_add.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); element_add.action = cdnrinfo->tce_un.element.action; if (ioctl(cdnr_fd, CDNR_ADD_ELEM, &element_add) < 0) { clinfo->handle = CDNR_NULL_HANDLE; return (QOPERR_SYSCALL); } clinfo->handle = element_add.cdnr_handle; break; case TCETYPE_TBMETER: memset(&tbmeter_add, 0, sizeof(tbmeter_add)); strncpy(tbmeter_add.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); tbmeter_add.profile = cdnrinfo->tce_un.tbmeter.profile; tbmeter_add.in_action = cdnrinfo->tce_un.tbmeter.in_action; tbmeter_add.out_action = cdnrinfo->tce_un.tbmeter.out_action; if (ioctl(cdnr_fd, CDNR_ADD_TBM, &tbmeter_add) < 0) { clinfo->handle = CDNR_NULL_HANDLE; return (QOPERR_SYSCALL); } clinfo->handle = tbmeter_add.cdnr_handle; break; case TCETYPE_TRTCM: memset(&trtcm_add, 0, sizeof(trtcm_add)); strncpy(trtcm_add.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); trtcm_add.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile; trtcm_add.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile; trtcm_add.green_action = cdnrinfo->tce_un.trtcm.green_action; trtcm_add.yellow_action = cdnrinfo->tce_un.trtcm.yellow_action; trtcm_add.red_action = cdnrinfo->tce_un.trtcm.red_action; trtcm_add.coloraware = cdnrinfo->tce_un.trtcm.coloraware; if (ioctl(cdnr_fd, CDNR_ADD_TCM, &trtcm_add) < 0) { clinfo->handle = CDNR_NULL_HANDLE; return (QOPERR_SYSCALL); } clinfo->handle = trtcm_add.cdnr_handle; break; case TCETYPE_TSWTCM: memset(&tswtcm_add, 0, sizeof(tswtcm_add)); strncpy(tswtcm_add.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); tswtcm_add.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate; tswtcm_add.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate; tswtcm_add.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval; tswtcm_add.green_action = cdnrinfo->tce_un.tswtcm.green_action; tswtcm_add.yellow_action = cdnrinfo->tce_un.tswtcm.yellow_action; tswtcm_add.red_action = cdnrinfo->tce_un.tswtcm.red_action; if (ioctl(cdnr_fd, CDNR_ADD_TSW, &tswtcm_add) < 0) { clinfo->handle = CDNR_NULL_HANDLE; return (QOPERR_SYSCALL); } clinfo->handle = tswtcm_add.cdnr_handle; break; default: return (QOPERR_CLASS_INVAL); } return (0); } static int cdnr_modify_class(struct classinfo *clinfo, void *arg) { struct cdnr_modify_tbmeter tbmeter_modify; struct cdnr_modify_trtcm trtcm_modify; struct cdnr_modify_tswtcm tswtcm_modify; struct cdnrinfo *cdnrinfo; cdnrinfo = clinfo->private; switch (cdnrinfo->tce_type) { case TCETYPE_TBMETER: memset(&tbmeter_modify, 0, sizeof(tbmeter_modify)); strncpy(tbmeter_modify.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); tbmeter_modify.cdnr_handle = clinfo->handle; tbmeter_modify.profile = cdnrinfo->tce_un.tbmeter.profile; if (ioctl(cdnr_fd, CDNR_MOD_TBM, &tbmeter_modify) < 0) return (QOPERR_SYSCALL); break; case TCETYPE_TRTCM: memset(&trtcm_modify, 0, sizeof(trtcm_modify)); strncpy(trtcm_modify.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); trtcm_modify.cdnr_handle = clinfo->handle; trtcm_modify.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile; trtcm_modify.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile; trtcm_modify.coloraware = cdnrinfo->tce_un.trtcm.coloraware; if (ioctl(cdnr_fd, CDNR_MOD_TCM, &trtcm_modify) < 0) return (QOPERR_SYSCALL); break; case TCETYPE_TSWTCM: memset(&tswtcm_modify, 0, sizeof(tswtcm_modify)); strncpy(tswtcm_modify.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); tswtcm_modify.cdnr_handle = clinfo->handle; tswtcm_modify.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate; tswtcm_modify.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate; tswtcm_modify.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval; if (ioctl(cdnr_fd, CDNR_MOD_TSW, &tswtcm_modify) < 0) return (QOPERR_SYSCALL); break; default: return (QOPERR_CLASS_INVAL); } return (0); } static int cdnr_delete_class(struct classinfo *clinfo) { struct cdnr_delete_element element_delete; if (clinfo->handle == CDNR_NULL_HANDLE) return (0); memset(&element_delete, 0, sizeof(element_delete)); strncpy(element_delete.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, IFNAMSIZ); element_delete.cdnr_handle = clinfo->handle; if (ioctl(cdnr_fd, CDNR_DEL_ELEM, &element_delete) < 0) return (QOPERR_SYSCALL); return (0); } static int cdnr_add_filter(struct fltrinfo *fltrinfo) { struct cdnr_add_filter fltr_add; memset(&fltr_add, 0, sizeof(fltr_add)); strncpy(fltr_add.iface.cdnr_ifname, fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ); fltr_add.cdnr_handle = fltrinfo->clinfo->handle; fltr_add.filter = fltrinfo->fltr; if (ioctl(cdnr_fd, CDNR_ADD_FILTER, &fltr_add) < 0) return (QOPERR_SYSCALL); fltrinfo->handle = fltr_add.filter_handle; return (0); } static int cdnr_delete_filter(struct fltrinfo *fltrinfo) { struct cdnr_delete_filter fltr_del; memset(&fltr_del, 0, sizeof(fltr_del)); strncpy(fltr_del.iface.cdnr_ifname, fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ); fltr_del.filter_handle = fltrinfo->handle; if (ioctl(cdnr_fd, CDNR_DEL_FILTER, &fltr_del) < 0) return (QOPERR_SYSCALL); return (0); } static int verify_tbprofile(struct tb_profile *profile, const char *cdnr_name) { if (profile->depth < 1500) { LOG(LOG_WARNING, 0, "warning: token bucket depth for %s is too small (%d)", cdnr_name, profile->depth); return (-1); } return (0); }