The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/altq/altq_cdnr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: altq_cdnr.c,v 1.19 2007/03/04 05:59:01 christos Exp $  */
    2 /*      $KAME: altq_cdnr.c,v 1.15 2005/04/13 03:44:24 suz Exp $ */
    3 
    4 /*
    5  * Copyright (C) 1999-2002
    6  *      Sony Computer Science Laboratories Inc.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __KERNEL_RCSID(0, "$NetBSD: altq_cdnr.c,v 1.19 2007/03/04 05:59:01 christos Exp $");
   32 
   33 #ifdef _KERNEL_OPT
   34 #include "opt_altq.h"
   35 #include "opt_inet.h"
   36 #endif
   37 
   38 #include <sys/param.h>
   39 #include <sys/malloc.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/socket.h>
   42 #include <sys/sockio.h>
   43 #include <sys/systm.h>
   44 #include <sys/proc.h>
   45 #include <sys/errno.h>
   46 #include <sys/kernel.h>
   47 #include <sys/queue.h>
   48 #include <sys/kauth.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_types.h>
   52 #include <netinet/in.h>
   53 #include <netinet/in_systm.h>
   54 #include <netinet/ip.h>
   55 #ifdef INET6
   56 #include <netinet/ip6.h>
   57 #endif
   58 
   59 #include <altq/altq.h>
   60 #include <altq/altq_conf.h>
   61 #include <altq/altq_cdnr.h>
   62 
   63 #ifdef ALTQ3_COMPAT
   64 /*
   65  * diffserv traffic conditioning module
   66  */
   67 
   68 int altq_cdnr_enabled = 0;
   69 
   70 /* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */
   71 #ifdef ALTQ_CDNR
   72 
   73 /* cdnr_list keeps all cdnr's allocated. */
   74 static LIST_HEAD(, top_cdnr) tcb_list;
   75 
   76 static int altq_cdnr_input(struct mbuf *, int);
   77 static struct top_cdnr *tcb_lookup(char *ifname);
   78 static struct cdnr_block *cdnr_handle2cb(u_long);
   79 static u_long cdnr_cb2handle(struct cdnr_block *);
   80 static void *cdnr_cballoc(struct top_cdnr *, int,
   81        struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *));
   82 static void cdnr_cbdestroy(void *);
   83 static int tca_verify_action(struct tc_action *);
   84 static void tca_import_action(struct tc_action *, struct tc_action *);
   85 static void tca_invalidate_action(struct tc_action *);
   86 
   87 static int generic_element_destroy(struct cdnr_block *);
   88 static struct top_cdnr *top_create(struct ifaltq *);
   89 static int top_destroy(struct top_cdnr *);
   90 static struct cdnr_block *element_create(struct top_cdnr *, struct tc_action *);
   91 static int element_destroy(struct cdnr_block *);
   92 static void tb_import_profile(struct tbe *, struct tb_profile *);
   93 static struct tbmeter *tbm_create(struct top_cdnr *, struct tb_profile *,
   94                                   struct tc_action *, struct tc_action *);
   95 static int tbm_destroy(struct tbmeter *);
   96 static struct tc_action *tbm_input(struct cdnr_block *, struct cdnr_pktinfo *);
   97 static struct trtcm *trtcm_create(struct top_cdnr *,
   98                   struct tb_profile *, struct tb_profile *,
   99                   struct tc_action *, struct tc_action *, struct tc_action *,
  100                   int);
  101 static int trtcm_destroy(struct trtcm *);
  102 static struct tc_action *trtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
  103 static struct tswtcm *tswtcm_create(struct top_cdnr *,
  104                   u_int32_t, u_int32_t, u_int32_t,
  105                   struct tc_action *, struct tc_action *, struct tc_action *);
  106 static int tswtcm_destroy(struct tswtcm *);
  107 static struct tc_action *tswtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
  108 
  109 static int cdnrcmd_if_attach(char *);
  110 static int cdnrcmd_if_detach(char *);
  111 static int cdnrcmd_add_element(struct cdnr_add_element *);
  112 static int cdnrcmd_delete_element(struct cdnr_delete_element *);
  113 static int cdnrcmd_add_filter(struct cdnr_add_filter *);
  114 static int cdnrcmd_delete_filter(struct cdnr_delete_filter *);
  115 static int cdnrcmd_add_tbm(struct cdnr_add_tbmeter *);
  116 static int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *);
  117 static int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *);
  118 static int cdnrcmd_add_trtcm(struct cdnr_add_trtcm *);
  119 static int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *);
  120 static int cdnrcmd_tcm_stats(struct cdnr_tcm_stats *);
  121 static int cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm *);
  122 static int cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm *);
  123 static int cdnrcmd_get_stats(struct cdnr_get_stats *);
  124 
  125 altqdev_decl(cdnr);
  126 
  127 /*
  128  * top level input function called from ip_input.
  129  * should be called before converting header fields to host-byte-order.
  130  */
  131 int
  132 altq_cdnr_input(struct mbuf *m, int af)
  133 {
  134         struct ifnet            *ifp;
  135         struct ip               *ip;
  136         struct top_cdnr         *top;
  137         struct tc_action        *tca;
  138         struct cdnr_block       *cb;
  139         struct cdnr_pktinfo     pktinfo;
  140 
  141         ifp = m->m_pkthdr.rcvif;
  142         if (!ALTQ_IS_CNDTNING(&ifp->if_snd))
  143                 /* traffic conditioner is not enabled on this interface */
  144                 return (1);
  145 
  146         top = ifp->if_snd.altq_cdnr;
  147 
  148         ip = mtod(m, struct ip *);
  149 #ifdef INET6
  150         if (af == AF_INET6) {
  151                 u_int32_t flowlabel;
  152 
  153                 flowlabel = ((struct ip6_hdr *)ip)->ip6_flow;
  154                 pktinfo.pkt_dscp = (ntohl(flowlabel) >> 20) & DSCP_MASK;
  155         } else
  156 #endif
  157                 pktinfo.pkt_dscp = ip->ip_tos & DSCP_MASK;
  158         pktinfo.pkt_len = m_pktlen(m);
  159 
  160         tca = NULL;
  161 
  162         cb = acc_classify(&top->tc_classifier, m, af);
  163         if (cb != NULL)
  164                 tca = &cb->cb_action;
  165 
  166         if (tca == NULL)
  167                 tca = &top->tc_block.cb_action;
  168 
  169         while (1) {
  170                 PKTCNTR_ADD(&top->tc_cnts[tca->tca_code], pktinfo.pkt_len);
  171 
  172                 switch (tca->tca_code) {
  173                 case TCACODE_PASS:
  174                         return (1);
  175                 case TCACODE_DROP:
  176                         m_freem(m);
  177                         return (0);
  178                 case TCACODE_RETURN:
  179                         return (0);
  180                 case TCACODE_MARK:
  181 #ifdef INET6
  182                         if (af == AF_INET6) {
  183                                 struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
  184                                 u_int32_t flowlabel;
  185 
  186                                 flowlabel = ntohl(ip6->ip6_flow);
  187                                 flowlabel = (tca->tca_dscp << 20) |
  188                                         (flowlabel & ~(DSCP_MASK << 20));
  189                                 ip6->ip6_flow = htonl(flowlabel);
  190                         } else
  191 #endif
  192                                 ip->ip_tos = tca->tca_dscp |
  193                                         (ip->ip_tos & DSCP_CUMASK);
  194                         return (1);
  195                 case TCACODE_NEXT:
  196                         cb = tca->tca_next;
  197                         tca = (*cb->cb_input)(cb, &pktinfo);
  198                         break;
  199                 case TCACODE_NONE:
  200                 default:
  201                         return (1);
  202                 }
  203         }
  204 }
  205 
  206 static struct top_cdnr *
  207 tcb_lookup(char *ifname)
  208 {
  209         struct top_cdnr *top;
  210         struct ifnet *ifp;
  211 
  212         if ((ifp = ifunit(ifname)) != NULL)
  213                 LIST_FOREACH(top, &tcb_list, tc_next)
  214                         if (top->tc_ifq->altq_ifp == ifp)
  215                                 return (top);
  216         return (NULL);
  217 }
  218 
  219 static struct cdnr_block *
  220 cdnr_handle2cb(u_long handle)
  221 {
  222         struct cdnr_block *cb;
  223 
  224         cb = (struct cdnr_block *)handle;
  225         if (handle != ALIGN(cb))
  226                 return (NULL);
  227 
  228         if (cb == NULL || cb->cb_handle != handle)
  229                 return (NULL);
  230         return (cb);
  231 }
  232 
  233 static u_long
  234 cdnr_cb2handle(struct cdnr_block *cb)
  235 {
  236         return (cb->cb_handle);
  237 }
  238 
  239 static void *
  240 cdnr_cballoc(struct top_cdnr *top, int type, struct tc_action *(*input_func)(
  241     struct cdnr_block *, struct cdnr_pktinfo *))
  242 {
  243         struct cdnr_block *cb;
  244         int size;
  245 
  246         switch (type) {
  247         case TCETYPE_TOP:
  248                 size = sizeof(struct top_cdnr);
  249                 break;
  250         case TCETYPE_ELEMENT:
  251                 size = sizeof(struct cdnr_block);
  252                 break;
  253         case TCETYPE_TBMETER:
  254                 size = sizeof(struct tbmeter);
  255                 break;
  256         case TCETYPE_TRTCM:
  257                 size = sizeof(struct trtcm);
  258                 break;
  259         case TCETYPE_TSWTCM:
  260                 size = sizeof(struct tswtcm);
  261                 break;
  262         default:
  263                 return (NULL);
  264         }
  265 
  266         cb = malloc(size, M_DEVBUF, M_WAITOK|M_ZERO);
  267         if (cb == NULL)
  268                 return (NULL);
  269 
  270         cb->cb_len = size;
  271         cb->cb_type = type;
  272         cb->cb_ref = 0;
  273         cb->cb_handle = (u_long)cb;
  274         if (top == NULL)
  275                 cb->cb_top = (struct top_cdnr *)cb;
  276         else
  277                 cb->cb_top = top;
  278 
  279         if (input_func != NULL) {
  280                 /*
  281                  * if this cdnr has an action function,
  282                  * make tc_action to call itself.
  283                  */
  284                 cb->cb_action.tca_code = TCACODE_NEXT;
  285                 cb->cb_action.tca_next = cb;
  286                 cb->cb_input = input_func;
  287         } else
  288                 cb->cb_action.tca_code = TCACODE_NONE;
  289 
  290         /* if this isn't top, register the element to the top level cdnr */
  291         if (top != NULL)
  292                 LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next);
  293 
  294         return ((void *)cb);
  295 }
  296 
  297 static void
  298 cdnr_cbdestroy(void *cblock)
  299 {
  300         struct cdnr_block *cb = cblock;
  301 
  302         /* delete filters belonging to this cdnr */
  303         acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0);
  304 
  305         /* remove from the top level cdnr */
  306         if (cb->cb_top != cblock)
  307                 LIST_REMOVE(cb, cb_next);
  308 
  309         free(cb, M_DEVBUF);
  310 }
  311 
  312 /*
  313  * conditioner common destroy routine
  314  */
  315 static int
  316 generic_element_destroy(struct cdnr_block *cb)
  317 {
  318         int error = 0;
  319 
  320         switch (cb->cb_type) {
  321         case TCETYPE_TOP:
  322                 error = top_destroy((struct top_cdnr *)cb);
  323                 break;
  324         case TCETYPE_ELEMENT:
  325                 error = element_destroy(cb);
  326                 break;
  327         case TCETYPE_TBMETER:
  328                 error = tbm_destroy((struct tbmeter *)cb);
  329                 break;
  330         case TCETYPE_TRTCM:
  331                 error = trtcm_destroy((struct trtcm *)cb);
  332                 break;
  333         case TCETYPE_TSWTCM:
  334                 error = tswtcm_destroy((struct tswtcm *)cb);
  335                 break;
  336         default:
  337                 error = EINVAL;
  338         }
  339         return (error);
  340 }
  341 
  342 static int
  343 tca_verify_action(struct tc_action *utca)
  344 {
  345         switch (utca->tca_code) {
  346         case TCACODE_PASS:
  347         case TCACODE_DROP:
  348         case TCACODE_MARK:
  349                 /* these are ok */
  350                 break;
  351 
  352         case TCACODE_HANDLE:
  353                 /* verify handle value */
  354                 if (cdnr_handle2cb(utca->tca_handle) == NULL)
  355                         return (-1);
  356                 break;
  357 
  358         case TCACODE_NONE:
  359         case TCACODE_RETURN:
  360         case TCACODE_NEXT:
  361         default:
  362                 /* should not be passed from a user */
  363                 return (-1);
  364         }
  365         return (0);
  366 }
  367 
  368 static void
  369 tca_import_action(struct tc_action *ktca, struct tc_action *utca)
  370 {
  371         struct cdnr_block *cb;
  372 
  373         *ktca = *utca;
  374         if (ktca->tca_code == TCACODE_HANDLE) {
  375                 cb = cdnr_handle2cb(ktca->tca_handle);
  376                 if (cb == NULL) {
  377                         ktca->tca_code = TCACODE_NONE;
  378                         return;
  379                 }
  380                 ktca->tca_code = TCACODE_NEXT;
  381                 ktca->tca_next = cb;
  382                 cb->cb_ref++;
  383         } else if (ktca->tca_code == TCACODE_MARK) {
  384                 ktca->tca_dscp &= DSCP_MASK;
  385         }
  386         return;
  387 }
  388 
  389 static void
  390 tca_invalidate_action(struct tc_action *tca)
  391 {
  392         struct cdnr_block *cb;
  393 
  394         if (tca->tca_code == TCACODE_NEXT) {
  395                 cb = tca->tca_next;
  396                 if (cb == NULL)
  397                         return;
  398                 cb->cb_ref--;
  399         }
  400         tca->tca_code = TCACODE_NONE;
  401 }
  402 
  403 /*
  404  * top level traffic conditioner
  405  */
  406 static struct top_cdnr *
  407 top_create(struct ifaltq *ifq)
  408 {
  409         struct top_cdnr *top;
  410 
  411         if ((top = cdnr_cballoc(NULL, TCETYPE_TOP, NULL)) == NULL)
  412                 return (NULL);
  413 
  414         top->tc_ifq = ifq;
  415         /* set default action for the top level conditioner */
  416         top->tc_block.cb_action.tca_code = TCACODE_PASS;
  417 
  418         LIST_INSERT_HEAD(&tcb_list, top, tc_next);
  419 
  420         ifq->altq_cdnr = top;
  421 
  422         return (top);
  423 }
  424 
  425 static int
  426 top_destroy(struct top_cdnr *top)
  427 {
  428         struct cdnr_block *cb;
  429 
  430         if (ALTQ_IS_CNDTNING(top->tc_ifq))
  431                 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
  432         top->tc_ifq->altq_cdnr = NULL;
  433 
  434         /*
  435          * destroy all the conditioner elements belonging to this interface
  436          */
  437         while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) {
  438                 while (cb != NULL && cb->cb_ref > 0)
  439                         cb = LIST_NEXT(cb, cb_next);
  440                 if (cb != NULL)
  441                         generic_element_destroy(cb);
  442         }
  443 
  444         LIST_REMOVE(top, tc_next);
  445 
  446         cdnr_cbdestroy(top);
  447 
  448         /* if there is no active conditioner, remove the input hook */
  449         if (altq_input != NULL) {
  450                 LIST_FOREACH(top, &tcb_list, tc_next)
  451                         if (ALTQ_IS_CNDTNING(top->tc_ifq))
  452                                 break;
  453                 if (top == NULL)
  454                         altq_input = NULL;
  455         }
  456 
  457         return (0);
  458 }
  459 
  460 /*
  461  * simple tc elements without input function (e.g., dropper and makers).
  462  */
  463 static struct cdnr_block *
  464 element_create(struct top_cdnr *top, struct tc_action *action)
  465 {
  466         struct cdnr_block *cb;
  467 
  468         if (tca_verify_action(action) < 0)
  469                 return (NULL);
  470 
  471         if ((cb = cdnr_cballoc(top, TCETYPE_ELEMENT, NULL)) == NULL)
  472                 return (NULL);
  473 
  474         tca_import_action(&cb->cb_action, action);
  475 
  476         return (cb);
  477 }
  478 
  479 static int
  480 element_destroy(struct cdnr_block *cb)
  481 {
  482         if (cb->cb_ref > 0)
  483                 return (EBUSY);
  484 
  485         tca_invalidate_action(&cb->cb_action);
  486 
  487         cdnr_cbdestroy(cb);
  488         return (0);
  489 }
  490 
  491 /*
  492  * internal representation of token bucket parameters
  493  *      rate:   byte_per_unittime << 32
  494  *              (((bits_per_sec) / 8) << 32) / machclk_freq
  495  *      depth:  byte << 32
  496  *
  497  */
  498 #define TB_SHIFT        32
  499 #define TB_SCALE(x)     ((u_int64_t)(x) << TB_SHIFT)
  500 #define TB_UNSCALE(x)   ((x) >> TB_SHIFT)
  501 
  502 static void
  503 tb_import_profile(struct tbe *tb, struct tb_profile *profile)
  504 {
  505         tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq;
  506         tb->depth = TB_SCALE(profile->depth);
  507         if (tb->rate > 0)
  508                 tb->filluptime = tb->depth / tb->rate;
  509         else
  510                 tb->filluptime = 0xffffffffffffffffLL;
  511         tb->token = tb->depth;
  512         tb->last = read_machclk();
  513 }
  514 
  515 /*
  516  * simple token bucket meter
  517  */
  518 static struct tbmeter *
  519 tbm_create(struct top_cdnr *top, struct tb_profile *profile,
  520     struct tc_action *in_action, struct tc_action *out_action)
  521 {
  522         struct tbmeter *tbm = NULL;
  523 
  524         if (tca_verify_action(in_action) < 0
  525             || tca_verify_action(out_action) < 0)
  526                 return (NULL);
  527 
  528         if ((tbm = cdnr_cballoc(top, TCETYPE_TBMETER,
  529                                 tbm_input)) == NULL)
  530                 return (NULL);
  531 
  532         tb_import_profile(&tbm->tb, profile);
  533 
  534         tca_import_action(&tbm->in_action, in_action);
  535         tca_import_action(&tbm->out_action, out_action);
  536 
  537         return (tbm);
  538 }
  539 
  540 static int
  541 tbm_destroy(struct tbmeter *tbm)
  542 {
  543         if (tbm->cdnrblk.cb_ref > 0)
  544                 return (EBUSY);
  545 
  546         tca_invalidate_action(&tbm->in_action);
  547         tca_invalidate_action(&tbm->out_action);
  548 
  549         cdnr_cbdestroy(tbm);
  550         return (0);
  551 }
  552 
  553 static struct tc_action *
  554 tbm_input(struct cdnr_block *cb, struct cdnr_pktinfo *pktinfo)
  555 {
  556         struct tbmeter *tbm = (struct tbmeter *)cb;
  557         u_int64_t       len;
  558         u_int64_t       interval, now;
  559 
  560         len = TB_SCALE(pktinfo->pkt_len);
  561 
  562         if (tbm->tb.token < len) {
  563                 now = read_machclk();
  564                 interval = now - tbm->tb.last;
  565                 if (interval >= tbm->tb.filluptime)
  566                         tbm->tb.token = tbm->tb.depth;
  567                 else {
  568                         tbm->tb.token += interval * tbm->tb.rate;
  569                         if (tbm->tb.token > tbm->tb.depth)
  570                                 tbm->tb.token = tbm->tb.depth;
  571                 }
  572                 tbm->tb.last = now;
  573         }
  574 
  575         if (tbm->tb.token < len) {
  576                 PKTCNTR_ADD(&tbm->out_cnt, pktinfo->pkt_len);
  577                 return (&tbm->out_action);
  578         }
  579 
  580         tbm->tb.token -= len;
  581         PKTCNTR_ADD(&tbm->in_cnt, pktinfo->pkt_len);
  582         return (&tbm->in_action);
  583 }
  584 
  585 /*
  586  * two rate three color marker
  587  * as described in draft-heinanen-diffserv-trtcm-01.txt
  588  */
  589 static struct trtcm *
  590 trtcm_create(struct top_cdnr *top, struct tb_profile *cmtd_profile,
  591     struct tb_profile *peak_profile, struct tc_action *green_action,
  592     struct tc_action *yellow_action, struct tc_action *red_action,
  593     int coloraware)
  594 {
  595         struct trtcm *tcm = NULL;
  596 
  597         if (tca_verify_action(green_action) < 0
  598             || tca_verify_action(yellow_action) < 0
  599             || tca_verify_action(red_action) < 0)
  600                 return (NULL);
  601 
  602         if ((tcm = cdnr_cballoc(top, TCETYPE_TRTCM,
  603                                 trtcm_input)) == NULL)
  604                 return (NULL);
  605 
  606         tb_import_profile(&tcm->cmtd_tb, cmtd_profile);
  607         tb_import_profile(&tcm->peak_tb, peak_profile);
  608 
  609         tca_import_action(&tcm->green_action, green_action);
  610         tca_import_action(&tcm->yellow_action, yellow_action);
  611         tca_import_action(&tcm->red_action, red_action);
  612 
  613         /* set dscps to use */
  614         if (tcm->green_action.tca_code == TCACODE_MARK)
  615                 tcm->green_dscp = tcm->green_action.tca_dscp & DSCP_MASK;
  616         else
  617                 tcm->green_dscp = DSCP_AF11;
  618         if (tcm->yellow_action.tca_code == TCACODE_MARK)
  619                 tcm->yellow_dscp = tcm->yellow_action.tca_dscp & DSCP_MASK;
  620         else
  621                 tcm->yellow_dscp = DSCP_AF12;
  622         if (tcm->red_action.tca_code == TCACODE_MARK)
  623                 tcm->red_dscp = tcm->red_action.tca_dscp & DSCP_MASK;
  624         else
  625                 tcm->red_dscp = DSCP_AF13;
  626 
  627         tcm->coloraware = coloraware;
  628 
  629         return (tcm);
  630 }
  631 
  632 static int
  633 trtcm_destroy(struct trtcm *tcm)
  634 {
  635         if (tcm->cdnrblk.cb_ref > 0)
  636                 return (EBUSY);
  637 
  638         tca_invalidate_action(&tcm->green_action);
  639         tca_invalidate_action(&tcm->yellow_action);
  640         tca_invalidate_action(&tcm->red_action);
  641 
  642         cdnr_cbdestroy(tcm);
  643         return (0);
  644 }
  645 
  646 static struct tc_action *
  647 trtcm_input(struct cdnr_block *cb, struct cdnr_pktinfo *pktinfo)
  648 {
  649         struct trtcm *tcm = (struct trtcm *)cb;
  650         u_int64_t       len;
  651         u_int64_t       interval, now;
  652         u_int8_t        color;
  653 
  654         len = TB_SCALE(pktinfo->pkt_len);
  655         if (tcm->coloraware) {
  656                 color = pktinfo->pkt_dscp;
  657                 if (color != tcm->yellow_dscp && color != tcm->red_dscp)
  658                         color = tcm->green_dscp;
  659         } else {
  660                 /* if color-blind, precolor it as green */
  661                 color = tcm->green_dscp;
  662         }
  663 
  664         now = read_machclk();
  665         if (tcm->cmtd_tb.token < len) {
  666                 interval = now - tcm->cmtd_tb.last;
  667                 if (interval >= tcm->cmtd_tb.filluptime)
  668                         tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
  669                 else {
  670                         tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate;
  671                         if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth)
  672                                 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
  673                 }
  674                 tcm->cmtd_tb.last = now;
  675         }
  676         if (tcm->peak_tb.token < len) {
  677                 interval = now - tcm->peak_tb.last;
  678                 if (interval >= tcm->peak_tb.filluptime)
  679                         tcm->peak_tb.token = tcm->peak_tb.depth;
  680                 else {
  681                         tcm->peak_tb.token += interval * tcm->peak_tb.rate;
  682                         if (tcm->peak_tb.token > tcm->peak_tb.depth)
  683                                 tcm->peak_tb.token = tcm->peak_tb.depth;
  684                 }
  685                 tcm->peak_tb.last = now;
  686         }
  687 
  688         if (color == tcm->red_dscp || tcm->peak_tb.token < len) {
  689                 pktinfo->pkt_dscp = tcm->red_dscp;
  690                 PKTCNTR_ADD(&tcm->red_cnt, pktinfo->pkt_len);
  691                 return (&tcm->red_action);
  692         }
  693 
  694         if (color == tcm->yellow_dscp || tcm->cmtd_tb.token < len) {
  695                 pktinfo->pkt_dscp = tcm->yellow_dscp;
  696                 tcm->peak_tb.token -= len;
  697                 PKTCNTR_ADD(&tcm->yellow_cnt, pktinfo->pkt_len);
  698                 return (&tcm->yellow_action);
  699         }
  700 
  701         pktinfo->pkt_dscp = tcm->green_dscp;
  702         tcm->cmtd_tb.token -= len;
  703         tcm->peak_tb.token -= len;
  704         PKTCNTR_ADD(&tcm->green_cnt, pktinfo->pkt_len);
  705         return (&tcm->green_action);
  706 }
  707 
  708 /*
  709  * time sliding window three color marker
  710  * as described in draft-fang-diffserv-tc-tswtcm-00.txt
  711  */
  712 static struct tswtcm *
  713 tswtcm_create(struct top_cdnr *top, u_int32_t cmtd_rate, u_int32_t peak_rate,
  714     u_int32_t avg_interval, struct tc_action *green_action,
  715     struct tc_action *yellow_action, struct tc_action *red_action)
  716 {
  717         struct tswtcm *tsw;
  718 
  719         if (tca_verify_action(green_action) < 0
  720             || tca_verify_action(yellow_action) < 0
  721             || tca_verify_action(red_action) < 0)
  722                 return (NULL);
  723 
  724         if ((tsw = cdnr_cballoc(top, TCETYPE_TSWTCM,
  725                                 tswtcm_input)) == NULL)
  726                 return (NULL);
  727 
  728         tca_import_action(&tsw->green_action, green_action);
  729         tca_import_action(&tsw->yellow_action, yellow_action);
  730         tca_import_action(&tsw->red_action, red_action);
  731 
  732         /* set dscps to use */
  733         if (tsw->green_action.tca_code == TCACODE_MARK)
  734                 tsw->green_dscp = tsw->green_action.tca_dscp & DSCP_MASK;
  735         else
  736                 tsw->green_dscp = DSCP_AF11;
  737         if (tsw->yellow_action.tca_code == TCACODE_MARK)
  738                 tsw->yellow_dscp = tsw->yellow_action.tca_dscp & DSCP_MASK;
  739         else
  740                 tsw->yellow_dscp = DSCP_AF12;
  741         if (tsw->red_action.tca_code == TCACODE_MARK)
  742                 tsw->red_dscp = tsw->red_action.tca_dscp & DSCP_MASK;
  743         else
  744                 tsw->red_dscp = DSCP_AF13;
  745 
  746         /* convert rates from bits/sec to bytes/sec */
  747         tsw->cmtd_rate = cmtd_rate / 8;
  748         tsw->peak_rate = peak_rate / 8;
  749         tsw->avg_rate = 0;
  750 
  751         /* timewin is converted from msec to machine clock unit */
  752         tsw->timewin = (u_int64_t)machclk_freq * avg_interval / 1000;
  753 
  754         return (tsw);
  755 }
  756 
  757 static int
  758 tswtcm_destroy(struct tswtcm *tsw)
  759 {
  760         if (tsw->cdnrblk.cb_ref > 0)
  761                 return (EBUSY);
  762 
  763         tca_invalidate_action(&tsw->green_action);
  764         tca_invalidate_action(&tsw->yellow_action);
  765         tca_invalidate_action(&tsw->red_action);
  766 
  767         cdnr_cbdestroy(tsw);
  768         return (0);
  769 }
  770 
  771 static struct tc_action *
  772 tswtcm_input(struct cdnr_block *cb, struct cdnr_pktinfo *pktinfo)
  773 {
  774         struct tswtcm   *tsw = (struct tswtcm *)cb;
  775         int             len;
  776         u_int32_t       avg_rate;
  777         u_int64_t       interval, now, tmp;
  778 
  779         /*
  780          * rate estimator
  781          */
  782         len = pktinfo->pkt_len;
  783         now = read_machclk();
  784 
  785         interval = now - tsw->t_front;
  786         /*
  787          * calculate average rate:
  788          *      avg = (avg * timewin + pkt_len)/(timewin + interval)
  789          * pkt_len needs to be multiplied by machclk_freq in order to
  790          * get (bytes/sec).
  791          * note: when avg_rate (bytes/sec) and timewin (machclk unit) are
  792          * less than 32 bits, the following 64-bit operation has enough
  793          * precision.
  794          */
  795         tmp = ((u_int64_t)tsw->avg_rate * tsw->timewin
  796                + (u_int64_t)len * machclk_freq) / (tsw->timewin + interval);
  797         tsw->avg_rate = avg_rate = (u_int32_t)tmp;
  798         tsw->t_front = now;
  799 
  800         /*
  801          * marker
  802          */
  803         if (avg_rate > tsw->cmtd_rate) {
  804                 u_int32_t randval = arc4random() % avg_rate;
  805 
  806                 if (avg_rate > tsw->peak_rate) {
  807                         if (randval < avg_rate - tsw->peak_rate) {
  808                                 /* mark red */
  809                                 pktinfo->pkt_dscp = tsw->red_dscp;
  810                                 PKTCNTR_ADD(&tsw->red_cnt, len);
  811                                 return (&tsw->red_action);
  812                         } else if (randval < avg_rate - tsw->cmtd_rate)
  813                                 goto mark_yellow;
  814                 } else {
  815                         /* peak_rate >= avg_rate > cmtd_rate */
  816                         if (randval < avg_rate - tsw->cmtd_rate) {
  817                         mark_yellow:
  818                                 pktinfo->pkt_dscp = tsw->yellow_dscp;
  819                                 PKTCNTR_ADD(&tsw->yellow_cnt, len);
  820                                 return (&tsw->yellow_action);
  821                         }
  822                 }
  823         }
  824 
  825         /* mark green */
  826         pktinfo->pkt_dscp = tsw->green_dscp;
  827         PKTCNTR_ADD(&tsw->green_cnt, len);
  828         return (&tsw->green_action);
  829 }
  830 
  831 /*
  832  * ioctl requests
  833  */
  834 static int
  835 cdnrcmd_if_attach(char *ifname)
  836 {
  837         struct ifnet *ifp;
  838         struct top_cdnr *top;
  839 
  840         if ((ifp = ifunit(ifname)) == NULL)
  841                 return (EBADF);
  842 
  843         if (ifp->if_snd.altq_cdnr != NULL)
  844                 return (EBUSY);
  845 
  846         if ((top = top_create(&ifp->if_snd)) == NULL)
  847                 return (ENOMEM);
  848         return (0);
  849 }
  850 
  851 static int
  852 cdnrcmd_if_detach(char *ifname)
  853 {
  854         struct top_cdnr *top;
  855 
  856         if ((top = tcb_lookup(ifname)) == NULL)
  857                 return (EBADF);
  858 
  859         return top_destroy(top);
  860 }
  861 
  862 static int
  863 cdnrcmd_add_element(struct cdnr_add_element *ap)
  864 {
  865         struct top_cdnr *top;
  866         struct cdnr_block *cb;
  867 
  868         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
  869                 return (EBADF);
  870 
  871         cb = element_create(top, &ap->action);
  872         if (cb == NULL)
  873                 return (EINVAL);
  874         /* return a class handle to the user */
  875         ap->cdnr_handle = cdnr_cb2handle(cb);
  876         return (0);
  877 }
  878 
  879 static int
  880 cdnrcmd_delete_element(struct cdnr_delete_element *ap)
  881 {
  882         struct top_cdnr *top;
  883         struct cdnr_block *cb;
  884 
  885         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
  886                 return (EBADF);
  887 
  888         if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
  889                 return (EINVAL);
  890 
  891         if (cb->cb_type != TCETYPE_ELEMENT)
  892                 return generic_element_destroy(cb);
  893 
  894         return element_destroy(cb);
  895 }
  896 
  897 static int
  898 cdnrcmd_add_filter(struct cdnr_add_filter *ap)
  899 {
  900         struct top_cdnr *top;
  901         struct cdnr_block *cb;
  902 
  903         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
  904                 return (EBADF);
  905 
  906         if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
  907                 return (EINVAL);
  908 
  909         return acc_add_filter(&top->tc_classifier, &ap->filter,
  910                               cb, &ap->filter_handle);
  911 }
  912 
  913 static int
  914 cdnrcmd_delete_filter(struct cdnr_delete_filter *ap)
  915 {
  916         struct top_cdnr *top;
  917 
  918         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
  919                 return (EBADF);
  920 
  921         return acc_delete_filter(&top->tc_classifier, ap->filter_handle);
  922 }
  923 
  924 static int
  925 cdnrcmd_add_tbm(struct cdnr_add_tbmeter *ap)
  926 {
  927         struct top_cdnr *top;
  928         struct tbmeter *tbm;
  929 
  930         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
  931                 return (EBADF);
  932 
  933         tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action);
  934         if (tbm == NULL)
  935                 return (EINVAL);
  936         /* return a class handle to the user */
  937         ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk);
  938         return (0);
  939 }
  940 
  941 static int
  942 cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *ap)
  943 {
  944         struct tbmeter *tbm;
  945 
  946         if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
  947                 return (EINVAL);
  948 
  949         tb_import_profile(&tbm->tb, &ap->profile);
  950 
  951         return (0);
  952 }
  953 
  954 static int
  955 cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *ap)
  956 {
  957         struct tbmeter *tbm;
  958 
  959         if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
  960                 return (EINVAL);
  961 
  962         ap->in_cnt = tbm->in_cnt;
  963         ap->out_cnt = tbm->out_cnt;
  964 
  965         return (0);
  966 }
  967 
  968 static int
  969 cdnrcmd_add_trtcm(struct cdnr_add_trtcm *ap)
  970 {
  971         struct top_cdnr *top;
  972         struct trtcm *tcm;
  973 
  974         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
  975                 return (EBADF);
  976 
  977         tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile,
  978                            &ap->green_action, &ap->yellow_action,
  979                            &ap->red_action, ap->coloraware);
  980         if (tcm == NULL)
  981                 return (EINVAL);
  982 
  983         /* return a class handle to the user */
  984         ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk);
  985         return (0);
  986 }
  987 
  988 static int
  989 cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *ap)
  990 {
  991         struct trtcm *tcm;
  992 
  993         if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
  994                 return (EINVAL);
  995 
  996         tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile);
  997         tb_import_profile(&tcm->peak_tb, &ap->peak_profile);
  998 
  999         return (0);
 1000 }
 1001 
 1002 static int
 1003 cdnrcmd_tcm_stats(struct cdnr_tcm_stats *ap)
 1004 {
 1005         struct cdnr_block *cb;
 1006 
 1007         if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
 1008                 return (EINVAL);
 1009 
 1010         if (cb->cb_type == TCETYPE_TRTCM) {
 1011                 struct trtcm *tcm = (struct trtcm *)cb;
 1012 
 1013                 ap->green_cnt = tcm->green_cnt;
 1014                 ap->yellow_cnt = tcm->yellow_cnt;
 1015                 ap->red_cnt = tcm->red_cnt;
 1016         } else if (cb->cb_type == TCETYPE_TSWTCM) {
 1017                 struct tswtcm *tsw = (struct tswtcm *)cb;
 1018 
 1019                 ap->green_cnt = tsw->green_cnt;
 1020                 ap->yellow_cnt = tsw->yellow_cnt;
 1021                 ap->red_cnt = tsw->red_cnt;
 1022         } else
 1023                 return (EINVAL);
 1024 
 1025         return (0);
 1026 }
 1027 
 1028 static int
 1029 cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm *ap)
 1030 {
 1031         struct top_cdnr *top;
 1032         struct tswtcm *tsw;
 1033 
 1034         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
 1035                 return (EBADF);
 1036 
 1037         if (ap->cmtd_rate > ap->peak_rate)
 1038                 return (EINVAL);
 1039 
 1040         tsw = tswtcm_create(top, ap->cmtd_rate, ap->peak_rate,
 1041                             ap->avg_interval, &ap->green_action,
 1042                             &ap->yellow_action, &ap->red_action);
 1043         if (tsw == NULL)
 1044                 return (EINVAL);
 1045 
 1046         /* return a class handle to the user */
 1047         ap->cdnr_handle = cdnr_cb2handle(&tsw->cdnrblk);
 1048         return (0);
 1049 }
 1050 
 1051 static int
 1052 cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm *ap)
 1053 {
 1054         struct tswtcm *tsw;
 1055 
 1056         if ((tsw = (struct tswtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
 1057                 return (EINVAL);
 1058 
 1059         if (ap->cmtd_rate > ap->peak_rate)
 1060                 return (EINVAL);
 1061 
 1062         /* convert rates from bits/sec to bytes/sec */
 1063         tsw->cmtd_rate = ap->cmtd_rate / 8;
 1064         tsw->peak_rate = ap->peak_rate / 8;
 1065         tsw->avg_rate = 0;
 1066 
 1067         /* timewin is converted from msec to machine clock unit */
 1068         tsw->timewin = (u_int64_t)machclk_freq * ap->avg_interval / 1000;
 1069 
 1070         return (0);
 1071 }
 1072 
 1073 static int
 1074 cdnrcmd_get_stats(struct cdnr_get_stats *ap)
 1075 {
 1076         struct top_cdnr *top;
 1077         struct cdnr_block *cb;
 1078         struct tbmeter *tbm;
 1079         struct trtcm *tcm;
 1080         struct tswtcm *tsw;
 1081         struct tce_stats tce, *usp;
 1082         int error, n, nskip, nelements;
 1083 
 1084         if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
 1085                 return (EBADF);
 1086 
 1087         /* copy action stats */
 1088         (void)memcpy(ap->cnts, top->tc_cnts, sizeof(ap->cnts));
 1089 
 1090         /* stats for each element */
 1091         nelements = ap->nelements;
 1092         usp = ap->tce_stats;
 1093         if (nelements <= 0 || usp == NULL)
 1094                 return (0);
 1095 
 1096         nskip = ap->nskip;
 1097         n = 0;
 1098         LIST_FOREACH(cb, &top->tc_elements, cb_next) {
 1099                 if (nskip > 0) {
 1100                         nskip--;
 1101                         continue;
 1102                 }
 1103 
 1104                 (void)memset(&tce, 0, sizeof(tce));
 1105                 tce.tce_handle = cb->cb_handle;
 1106                 tce.tce_type = cb->cb_type;
 1107                 switch (cb->cb_type) {
 1108                 case TCETYPE_TBMETER:
 1109                         tbm = (struct tbmeter *)cb;
 1110                         tce.tce_cnts[0] = tbm->in_cnt;
 1111                         tce.tce_cnts[1] = tbm->out_cnt;
 1112                         break;
 1113                 case TCETYPE_TRTCM:
 1114                         tcm = (struct trtcm *)cb;
 1115                         tce.tce_cnts[0] = tcm->green_cnt;
 1116                         tce.tce_cnts[1] = tcm->yellow_cnt;
 1117                         tce.tce_cnts[2] = tcm->red_cnt;
 1118                         break;
 1119                 case TCETYPE_TSWTCM:
 1120                         tsw = (struct tswtcm *)cb;
 1121                         tce.tce_cnts[0] = tsw->green_cnt;
 1122                         tce.tce_cnts[1] = tsw->yellow_cnt;
 1123                         tce.tce_cnts[2] = tsw->red_cnt;
 1124                         break;
 1125                 default:
 1126                         continue;
 1127                 }
 1128 
 1129                 if ((error = copyout((void *)&tce, (void *)usp++,
 1130                                      sizeof(tce))) != 0)
 1131                         return (error);
 1132 
 1133                 if (++n == nelements)
 1134                         break;
 1135         }
 1136         ap->nelements = n;
 1137 
 1138         return (0);
 1139 }
 1140 
 1141 /*
 1142  * conditioner device interface
 1143  */
 1144 int
 1145 cdnropen(dev_t dev, int flag, int fmt,
 1146     struct lwp *l)
 1147 {
 1148         if (machclk_freq == 0)
 1149                 init_machclk();
 1150 
 1151         if (machclk_freq == 0) {
 1152                 printf("cdnr: no CPU clock available!\n");
 1153                 return (ENXIO);
 1154         }
 1155 
 1156         /* everything will be done when the queueing scheme is attached. */
 1157         return 0;
 1158 }
 1159 
 1160 int
 1161 cdnrclose(dev_t dev, int flag, int fmt,
 1162     struct lwp *l)
 1163 {
 1164         struct top_cdnr *top;
 1165         int err, error = 0;
 1166 
 1167         while ((top = LIST_FIRST(&tcb_list)) != NULL) {
 1168                 /* destroy all */
 1169                 err = top_destroy(top);
 1170                 if (err != 0 && error == 0)
 1171                         error = err;
 1172         }
 1173         altq_input = NULL;
 1174 
 1175         return (error);
 1176 }
 1177 
 1178 int
 1179 cdnrioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag,
 1180     struct lwp *l)
 1181 {
 1182         struct top_cdnr *top;
 1183         struct cdnr_interface *ifacep;
 1184         int     s, error = 0;
 1185 
 1186         /* check super-user privilege */
 1187         switch (cmd) {
 1188         case CDNR_GETSTATS:
 1189                 break;
 1190         default:
 1191 #if (__FreeBSD_version > 400000)
 1192                 if ((error = suser(p)) != 0)
 1193 #else
 1194                 if ((error = kauth_authorize_network(l->l_cred,
 1195                     KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_CDNR, NULL,
 1196                     NULL, NULL)) != 0)
 1197 #endif
 1198                         return (error);
 1199                 break;
 1200         }
 1201 
 1202         s = splnet();
 1203         switch (cmd) {
 1204 
 1205         case CDNR_IF_ATTACH:
 1206                 ifacep = (struct cdnr_interface *)addr;
 1207                 error = cdnrcmd_if_attach(ifacep->cdnr_ifname);
 1208                 break;
 1209 
 1210         case CDNR_IF_DETACH:
 1211                 ifacep = (struct cdnr_interface *)addr;
 1212                 error = cdnrcmd_if_detach(ifacep->cdnr_ifname);
 1213                 break;
 1214 
 1215         case CDNR_ENABLE:
 1216         case CDNR_DISABLE:
 1217                 ifacep = (struct cdnr_interface *)addr;
 1218                 if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) {
 1219                         error = EBADF;
 1220                         break;
 1221                 }
 1222 
 1223                 switch (cmd) {
 1224 
 1225                 case CDNR_ENABLE:
 1226                         ALTQ_SET_CNDTNING(top->tc_ifq);
 1227                         if (altq_input == NULL)
 1228                                 altq_input = altq_cdnr_input;
 1229                         break;
 1230 
 1231                 case CDNR_DISABLE:
 1232                         ALTQ_CLEAR_CNDTNING(top->tc_ifq);
 1233                         LIST_FOREACH(top, &tcb_list, tc_next)
 1234                                 if (ALTQ_IS_CNDTNING(top->tc_ifq))
 1235                                         break;
 1236                         if (top == NULL)
 1237                                 altq_input = NULL;
 1238                         break;
 1239                 }
 1240                 break;
 1241 
 1242         case CDNR_ADD_ELEM:
 1243                 error = cdnrcmd_add_element((struct cdnr_add_element *)addr);
 1244                 break;
 1245 
 1246         case CDNR_DEL_ELEM:
 1247                 error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr);
 1248                 break;
 1249 
 1250         case CDNR_ADD_TBM:
 1251                 error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr);
 1252                 break;
 1253 
 1254         case CDNR_MOD_TBM:
 1255                 error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr);
 1256                 break;
 1257 
 1258         case CDNR_TBM_STATS:
 1259                 error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr);
 1260                 break;
 1261 
 1262         case CDNR_ADD_TCM:
 1263                 error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr);
 1264                 break;
 1265 
 1266         case CDNR_MOD_TCM:
 1267                 error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr);
 1268                 break;
 1269 
 1270         case CDNR_TCM_STATS:
 1271                 error = cdnrcmd_tcm_stats((struct cdnr_tcm_stats *)addr);
 1272                 break;
 1273 
 1274         case CDNR_ADD_FILTER:
 1275                 error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr);
 1276                 break;
 1277 
 1278         case CDNR_DEL_FILTER:
 1279                 error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr);
 1280                 break;
 1281 
 1282         case CDNR_GETSTATS:
 1283                 error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr);
 1284                 break;
 1285 
 1286         case CDNR_ADD_TSW:
 1287                 error = cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm *)addr);
 1288                 break;
 1289 
 1290         case CDNR_MOD_TSW:
 1291                 error = cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm *)addr);
 1292                 break;
 1293 
 1294         default:
 1295                 error = EINVAL;
 1296                 break;
 1297         }
 1298         splx(s);
 1299 
 1300         return error;
 1301 }
 1302 
 1303 #ifdef KLD_MODULE
 1304 
 1305 static struct altqsw cdnr_sw =
 1306         {"cdnr", cdnropen, cdnrclose, cdnrioctl};
 1307 
 1308 ALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw);
 1309 
 1310 #endif /* KLD_MODULE */
 1311 
 1312 #endif /* ALTQ3_COMPAT */
 1313 #endif /* ALTQ_CDNR */

Cache object: ceb7698e18cebe1135ec10c82bba1630


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.