[BACK]Return to altq_cdnr.c CVS log [TXT][DIR] Up to [local] / sys / altq

Annotation of sys/altq/altq_cdnr.c, Revision 1.1

1.1     ! nbrk        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: }

CVSweb