root/altq/altq_cdnr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. LIST_HEAD
  2. altq_cdnr_input
  3. tcb_lookup
  4. cdnr_handle2cb
  5. cdnr_cb2handle
  6. cdnr_cballoc
  7. cdnr_cbdestroy
  8. generic_element_destroy
  9. tca_verify_action
  10. tca_import_action
  11. tca_invalidate_action
  12. top_create
  13. top_destroy
  14. element_create
  15. element_destroy
  16. tb_import_profile
  17. tbm_create
  18. tbm_destroy
  19. tbm_input
  20. trtcm_create
  21. trtcm_destroy
  22. trtcm_input
  23. tswtcm_create
  24. tswtcm_destroy
  25. tswtcm_input
  26. cdnrcmd_if_attach
  27. cdnrcmd_if_detach
  28. cdnrcmd_add_element
  29. cdnrcmd_delete_element
  30. cdnrcmd_add_tbm
  31. cdnrcmd_modify_tbm
  32. cdnrcmd_tbm_stats
  33. cdnrcmd_add_trtcm
  34. cdnrcmd_modify_trtcm
  35. cdnrcmd_tcm_stats
  36. cdnrcmd_add_tswtcm
  37. cdnrcmd_modify_tswtcm
  38. cdnrcmd_get_stats

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

/* [<][>][^][v][top][bottom][index][help] */