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

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

1.1     ! nbrk        1: /*     $OpenBSD: altq_cbq.c,v 1.22 2007/05/28 17:16:38 henning Exp $   */
        !             2: /*     $KAME: altq_cbq.c,v 1.9 2000/12/14 08:12:45 thorpej Exp $       */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  *
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  *
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  *
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *      This product includes software developed by the SMCC Technology
        !            21:  *      Development Group at Sun Microsystems, Inc.
        !            22:  *
        !            23:  * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
        !            24:  *      promote products derived from this software without specific prior
        !            25:  *      written permission.
        !            26:  *
        !            27:  * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
        !            28:  * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is
        !            29:  * provided "as is" without express or implied warranty of any kind.
        !            30:  *
        !            31:  * These notices must be retained in any copies of any part of this software.
        !            32:  */
        !            33:
        !            34: #include <sys/param.h>
        !            35: #include <sys/malloc.h>
        !            36: #include <sys/mbuf.h>
        !            37: #include <sys/socket.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/errno.h>
        !            40: #include <sys/time.h>
        !            41:
        !            42: #include <net/if.h>
        !            43: #include <netinet/in.h>
        !            44:
        !            45: #include <net/pfvar.h>
        !            46: #include <altq/altq.h>
        !            47: #include <altq/altq_cbq.h>
        !            48:
        !            49: /*
        !            50:  * Forward Declarations.
        !            51:  */
        !            52: static int              cbq_class_destroy(cbq_state_t *, struct rm_class *);
        !            53: static struct rm_class  *clh_to_clp(cbq_state_t *, u_int32_t);
        !            54: static int              cbq_clear_interface(cbq_state_t *);
        !            55: static int              cbq_request(struct ifaltq *, int, void *);
        !            56: static int              cbq_enqueue(struct ifaltq *, struct mbuf *,
        !            57:                             struct altq_pktattr *);
        !            58: static struct mbuf     *cbq_dequeue(struct ifaltq *, int);
        !            59: static void             cbqrestart(struct ifaltq *);
        !            60: static void             get_class_stats(class_stats_t *, struct rm_class *);
        !            61: static void             cbq_purge(cbq_state_t *);
        !            62:
        !            63: /*
        !            64:  * int
        !            65:  * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This
        !            66:  *     function destroys a given traffic class.  Before destroying
        !            67:  *     the class, all traffic for that class is released.
        !            68:  */
        !            69: static int
        !            70: cbq_class_destroy(cbq_state_t *cbqp, struct rm_class *cl)
        !            71: {
        !            72:        int     i;
        !            73:
        !            74:        /* delete the class */
        !            75:        rmc_delete_class(&cbqp->ifnp, cl);
        !            76:
        !            77:        /*
        !            78:         * free the class handle
        !            79:         */
        !            80:        for (i = 0; i < CBQ_MAX_CLASSES; i++)
        !            81:                if (cbqp->cbq_class_tbl[i] == cl)
        !            82:                        cbqp->cbq_class_tbl[i] = NULL;
        !            83:
        !            84:        if (cl == cbqp->ifnp.root_)
        !            85:                cbqp->ifnp.root_ = NULL;
        !            86:        if (cl == cbqp->ifnp.default_)
        !            87:                cbqp->ifnp.default_ = NULL;
        !            88:        return (0);
        !            89: }
        !            90:
        !            91: /* convert class handle to class pointer */
        !            92: static struct rm_class *
        !            93: clh_to_clp(cbq_state_t *cbqp, u_int32_t chandle)
        !            94: {
        !            95:        int i;
        !            96:        struct rm_class *cl;
        !            97:
        !            98:        if (chandle == 0)
        !            99:                return (NULL);
        !           100:        /*
        !           101:         * first, try the slot corresponding to the lower bits of the handle.
        !           102:         * if it does not match, do the linear table search.
        !           103:         */
        !           104:        i = chandle % CBQ_MAX_CLASSES;
        !           105:        if ((cl = cbqp->cbq_class_tbl[i]) != NULL &&
        !           106:            cl->stats_.handle == chandle)
        !           107:                return (cl);
        !           108:        for (i = 0; i < CBQ_MAX_CLASSES; i++)
        !           109:                if ((cl = cbqp->cbq_class_tbl[i]) != NULL &&
        !           110:                    cl->stats_.handle == chandle)
        !           111:                        return (cl);
        !           112:        return (NULL);
        !           113: }
        !           114:
        !           115: static int
        !           116: cbq_clear_interface(cbq_state_t *cbqp)
        !           117: {
        !           118:        int              again, i;
        !           119:        struct rm_class *cl;
        !           120:
        !           121:        /* clear out the classes now */
        !           122:        do {
        !           123:                again = 0;
        !           124:                for (i = 0; i < CBQ_MAX_CLASSES; i++) {
        !           125:                        if ((cl = cbqp->cbq_class_tbl[i]) != NULL) {
        !           126:                                if (is_a_parent_class(cl))
        !           127:                                        again++;
        !           128:                                else {
        !           129:                                        cbq_class_destroy(cbqp, cl);
        !           130:                                        cbqp->cbq_class_tbl[i] = NULL;
        !           131:                                        if (cl == cbqp->ifnp.root_)
        !           132:                                                cbqp->ifnp.root_ = NULL;
        !           133:                                        if (cl == cbqp->ifnp.default_)
        !           134:                                                cbqp->ifnp.default_ = NULL;
        !           135:                                }
        !           136:                        }
        !           137:                }
        !           138:        } while (again);
        !           139:
        !           140:        return (0);
        !           141: }
        !           142:
        !           143: static int
        !           144: cbq_request(struct ifaltq *ifq, int req, void *arg)
        !           145: {
        !           146:        cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
        !           147:
        !           148:        switch (req) {
        !           149:        case ALTRQ_PURGE:
        !           150:                cbq_purge(cbqp);
        !           151:                break;
        !           152:        }
        !           153:        return (0);
        !           154: }
        !           155:
        !           156: /* copy the stats info in rm_class to class_states_t */
        !           157: static void
        !           158: get_class_stats(class_stats_t *statsp, struct rm_class *cl)
        !           159: {
        !           160:        statsp->handle          = cl->stats_.handle;
        !           161:        statsp->xmit_cnt        = cl->stats_.xmit_cnt;
        !           162:        statsp->drop_cnt        = cl->stats_.drop_cnt;
        !           163:        statsp->over            = cl->stats_.over;
        !           164:        statsp->borrows         = cl->stats_.borrows;
        !           165:        statsp->overactions     = cl->stats_.overactions;
        !           166:        statsp->delays          = cl->stats_.delays;
        !           167:
        !           168:        statsp->depth           = cl->depth_;
        !           169:        statsp->priority        = cl->pri_;
        !           170:        statsp->maxidle         = cl->maxidle_;
        !           171:        statsp->minidle         = cl->minidle_;
        !           172:        statsp->offtime         = cl->offtime_;
        !           173:        statsp->qmax            = qlimit(cl->q_);
        !           174:        statsp->ns_per_byte     = cl->ns_per_byte_;
        !           175:        statsp->wrr_allot       = cl->w_allotment_;
        !           176:        statsp->qcnt            = qlen(cl->q_);
        !           177:        statsp->avgidle         = cl->avgidle_;
        !           178:
        !           179:        statsp->qtype           = qtype(cl->q_);
        !           180: #ifdef ALTQ_RED
        !           181:        if (q_is_red(cl->q_))
        !           182:                red_getstats(cl->red_, &statsp->red[0]);
        !           183: #endif
        !           184: #ifdef ALTQ_RIO
        !           185:        if (q_is_rio(cl->q_))
        !           186:                rio_getstats((rio_t *)cl->red_, &statsp->red[0]);
        !           187: #endif
        !           188: }
        !           189:
        !           190: int
        !           191: cbq_pfattach(struct pf_altq *a)
        !           192: {
        !           193:        struct ifnet    *ifp;
        !           194:        int              s, error;
        !           195:
        !           196:        if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
        !           197:                return (EINVAL);
        !           198:        s = splnet();
        !           199:        error = altq_attach(&ifp->if_snd, ALTQT_CBQ, a->altq_disc,
        !           200:            cbq_enqueue, cbq_dequeue, cbq_request, NULL, NULL);
        !           201:        splx(s);
        !           202:        return (error);
        !           203: }
        !           204:
        !           205: int
        !           206: cbq_add_altq(struct pf_altq *a)
        !           207: {
        !           208:        cbq_state_t     *cbqp;
        !           209:        struct ifnet    *ifp;
        !           210:
        !           211:        if ((ifp = ifunit(a->ifname)) == NULL)
        !           212:                return (EINVAL);
        !           213:        if (!ALTQ_IS_READY(&ifp->if_snd))
        !           214:                return (ENODEV);
        !           215:
        !           216:        /* allocate and initialize cbq_state_t */
        !           217:        MALLOC(cbqp, cbq_state_t *, sizeof(cbq_state_t), M_DEVBUF, M_WAITOK);
        !           218:        if (cbqp == NULL)
        !           219:                return (ENOMEM);
        !           220:        bzero(cbqp, sizeof(cbq_state_t));
        !           221:        CALLOUT_INIT(&cbqp->cbq_callout);
        !           222:        cbqp->cbq_qlen = 0;
        !           223:        cbqp->ifnp.ifq_ = &ifp->if_snd;     /* keep the ifq */
        !           224:
        !           225:        /* keep the state in pf_altq */
        !           226:        a->altq_disc = cbqp;
        !           227:
        !           228:        return (0);
        !           229: }
        !           230:
        !           231: int
        !           232: cbq_remove_altq(struct pf_altq *a)
        !           233: {
        !           234:        cbq_state_t     *cbqp;
        !           235:
        !           236:        if ((cbqp = a->altq_disc) == NULL)
        !           237:                return (EINVAL);
        !           238:        a->altq_disc = NULL;
        !           239:
        !           240:        cbq_clear_interface(cbqp);
        !           241:
        !           242:        if (cbqp->ifnp.default_)
        !           243:                cbq_class_destroy(cbqp, cbqp->ifnp.default_);
        !           244:        if (cbqp->ifnp.root_)
        !           245:                cbq_class_destroy(cbqp, cbqp->ifnp.root_);
        !           246:
        !           247:        /* deallocate cbq_state_t */
        !           248:        FREE(cbqp, M_DEVBUF);
        !           249:
        !           250:        return (0);
        !           251: }
        !           252:
        !           253: int
        !           254: cbq_add_queue(struct pf_altq *a)
        !           255: {
        !           256:        struct rm_class *borrow, *parent;
        !           257:        cbq_state_t     *cbqp;
        !           258:        struct rm_class *cl;
        !           259:        struct cbq_opts *opts;
        !           260:        int             i;
        !           261:
        !           262:        if ((cbqp = a->altq_disc) == NULL)
        !           263:                return (EINVAL);
        !           264:        if (a->qid == 0)
        !           265:                return (EINVAL);
        !           266:
        !           267:        /*
        !           268:         * find a free slot in the class table.  if the slot matching
        !           269:         * the lower bits of qid is free, use this slot.  otherwise,
        !           270:         * use the first free slot.
        !           271:         */
        !           272:        i = a->qid % CBQ_MAX_CLASSES;
        !           273:        if (cbqp->cbq_class_tbl[i] != NULL) {
        !           274:                for (i = 0; i < CBQ_MAX_CLASSES; i++)
        !           275:                        if (cbqp->cbq_class_tbl[i] == NULL)
        !           276:                                break;
        !           277:                if (i == CBQ_MAX_CLASSES)
        !           278:                        return (EINVAL);
        !           279:        }
        !           280:
        !           281:        opts = &a->pq_u.cbq_opts;
        !           282:        /* check parameters */
        !           283:        if (a->priority >= CBQ_MAXPRI)
        !           284:                return (EINVAL);
        !           285:
        !           286:        /* Get pointers to parent and borrow classes.  */
        !           287:        parent = clh_to_clp(cbqp, a->parent_qid);
        !           288:        if (opts->flags & CBQCLF_BORROW)
        !           289:                borrow = parent;
        !           290:        else
        !           291:                borrow = NULL;
        !           292:
        !           293:        /*
        !           294:         * A class must borrow from its parent or it can not
        !           295:         * borrow at all.  Hence, borrow can be null.
        !           296:         */
        !           297:        if (parent == NULL && (opts->flags & CBQCLF_ROOTCLASS) == 0) {
        !           298:                printf("cbq_add_queue: no parent class!\n");
        !           299:                return (EINVAL);
        !           300:        }
        !           301:
        !           302:        if ((borrow != parent)  && (borrow != NULL)) {
        !           303:                printf("cbq_add_class: borrow class != parent\n");
        !           304:                return (EINVAL);
        !           305:        }
        !           306:
        !           307:        /*
        !           308:         * check parameters
        !           309:         */
        !           310:        switch (opts->flags & CBQCLF_CLASSMASK) {
        !           311:        case CBQCLF_ROOTCLASS:
        !           312:                if (parent != NULL)
        !           313:                        return (EINVAL);
        !           314:                if (cbqp->ifnp.root_)
        !           315:                        return (EINVAL);
        !           316:                break;
        !           317:        case CBQCLF_DEFCLASS:
        !           318:                if (cbqp->ifnp.default_)
        !           319:                        return (EINVAL);
        !           320:                break;
        !           321:        case 0:
        !           322:                if (a->qid == 0)
        !           323:                        return (EINVAL);
        !           324:                break;
        !           325:        default:
        !           326:                /* more than two flags bits set */
        !           327:                return (EINVAL);
        !           328:        }
        !           329:
        !           330:        /*
        !           331:         * create a class.  if this is a root class, initialize the
        !           332:         * interface.
        !           333:         */
        !           334:        if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) {
        !           335:                rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, opts->ns_per_byte,
        !           336:                    cbqrestart, a->qlimit, RM_MAXQUEUED,
        !           337:                    opts->maxidle, opts->minidle, opts->offtime,
        !           338:                    opts->flags);
        !           339:                cl = cbqp->ifnp.root_;
        !           340:        } else {
        !           341:                cl = rmc_newclass(a->priority,
        !           342:                                  &cbqp->ifnp, opts->ns_per_byte,
        !           343:                                  rmc_delay_action, a->qlimit, parent, borrow,
        !           344:                                  opts->maxidle, opts->minidle, opts->offtime,
        !           345:                                  opts->pktsize, opts->flags);
        !           346:        }
        !           347:        if (cl == NULL)
        !           348:                return (ENOMEM);
        !           349:
        !           350:        /* return handle to user space. */
        !           351:        cl->stats_.handle = a->qid;
        !           352:        cl->stats_.depth = cl->depth_;
        !           353:
        !           354:        /* save the allocated class */
        !           355:        cbqp->cbq_class_tbl[i] = cl;
        !           356:
        !           357:        if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS)
        !           358:                cbqp->ifnp.default_ = cl;
        !           359:
        !           360:        return (0);
        !           361: }
        !           362:
        !           363: int
        !           364: cbq_remove_queue(struct pf_altq *a)
        !           365: {
        !           366:        struct rm_class *cl;
        !           367:        cbq_state_t     *cbqp;
        !           368:        int             i;
        !           369:
        !           370:        if ((cbqp = a->altq_disc) == NULL)
        !           371:                return (EINVAL);
        !           372:
        !           373:        if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
        !           374:                return (EINVAL);
        !           375:
        !           376:        /* if we are a parent class, then return an error. */
        !           377:        if (is_a_parent_class(cl))
        !           378:                return (EINVAL);
        !           379:
        !           380:        /* delete the class */
        !           381:        rmc_delete_class(&cbqp->ifnp, cl);
        !           382:
        !           383:        /*
        !           384:         * free the class handle
        !           385:         */
        !           386:        for (i = 0; i < CBQ_MAX_CLASSES; i++)
        !           387:                if (cbqp->cbq_class_tbl[i] == cl) {
        !           388:                        cbqp->cbq_class_tbl[i] = NULL;
        !           389:                        if (cl == cbqp->ifnp.root_)
        !           390:                                cbqp->ifnp.root_ = NULL;
        !           391:                        if (cl == cbqp->ifnp.default_)
        !           392:                                cbqp->ifnp.default_ = NULL;
        !           393:                        break;
        !           394:                }
        !           395:
        !           396:        return (0);
        !           397: }
        !           398:
        !           399: int
        !           400: cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
        !           401: {
        !           402:        cbq_state_t     *cbqp;
        !           403:        struct rm_class *cl;
        !           404:        class_stats_t    stats;
        !           405:        int              error = 0;
        !           406:
        !           407:        if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL)
        !           408:                return (EBADF);
        !           409:
        !           410:        if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
        !           411:                return (EINVAL);
        !           412:
        !           413:        if (*nbytes < sizeof(stats))
        !           414:                return (EINVAL);
        !           415:
        !           416:        get_class_stats(&stats, cl);
        !           417:
        !           418:        if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
        !           419:                return (error);
        !           420:        *nbytes = sizeof(stats);
        !           421:        return (0);
        !           422: }
        !           423:
        !           424: /*
        !           425:  * int
        !           426:  * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr)
        !           427:  *             - Queue data packets.
        !           428:  *
        !           429:  *     cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
        !           430:  *     layer (e.g. ether_output).  cbq_enqueue queues the given packet
        !           431:  *     to the cbq, then invokes the driver's start routine.
        !           432:  *
        !           433:  *     Assumptions:    called in splnet
        !           434:  *     Returns:        0 if the queueing is successful.
        !           435:  *                     ENOBUFS if a packet dropping occurred as a result of
        !           436:  *                     the queueing.
        !           437:  */
        !           438:
        !           439: static int
        !           440: cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
        !           441: {
        !           442:        cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
        !           443:        struct rm_class *cl;
        !           444:        int              len;
        !           445:
        !           446:        /* grab class set by classifier */
        !           447:        if ((m->m_flags & M_PKTHDR) == 0) {
        !           448:                /* should not happen */
        !           449:                printf("altq: packet for %s does not have pkthdr\n",
        !           450:                    ifq->altq_ifp->if_xname);
        !           451:                m_freem(m);
        !           452:                return (ENOBUFS);
        !           453:        }
        !           454:        if ((cl = clh_to_clp(cbqp, m->m_pkthdr.pf.qid)) == NULL) {
        !           455:                cl = cbqp->ifnp.default_;
        !           456:                if (cl == NULL) {
        !           457:                        m_freem(m);
        !           458:                        return (ENOBUFS);
        !           459:                }
        !           460:                cl->pktattr_ = NULL;
        !           461:        }
        !           462:
        !           463:        len = m_pktlen(m);
        !           464:        if (rmc_queue_packet(cl, m) != 0) {
        !           465:                /* drop occurred.  some mbuf was freed in rmc_queue_packet. */
        !           466:                PKTCNTR_ADD(&cl->stats_.drop_cnt, len);
        !           467:                return (ENOBUFS);
        !           468:        }
        !           469:
        !           470:        /* successfully queued. */
        !           471:        ++cbqp->cbq_qlen;
        !           472:        IFQ_INC_LEN(ifq);
        !           473:        return (0);
        !           474: }
        !           475:
        !           476: static struct mbuf *
        !           477: cbq_dequeue(struct ifaltq *ifq, int op)
        !           478: {
        !           479:        cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
        !           480:        struct mbuf     *m;
        !           481:
        !           482:        m = rmc_dequeue_next(&cbqp->ifnp, op);
        !           483:
        !           484:        if (m && op == ALTDQ_REMOVE) {
        !           485:                --cbqp->cbq_qlen;  /* decrement # of packets in cbq */
        !           486:                IFQ_DEC_LEN(ifq);
        !           487:
        !           488:                /* Update the class. */
        !           489:                rmc_update_class_util(&cbqp->ifnp);
        !           490:        }
        !           491:        return (m);
        !           492: }
        !           493:
        !           494: /*
        !           495:  * void
        !           496:  * cbqrestart(queue_t *) - Restart sending of data.
        !           497:  * called from rmc_restart in splnet via timeout after waking up
        !           498:  * a suspended class.
        !           499:  *     Returns:        NONE
        !           500:  */
        !           501:
        !           502: static void
        !           503: cbqrestart(struct ifaltq *ifq)
        !           504: {
        !           505:        cbq_state_t     *cbqp;
        !           506:        struct ifnet    *ifp;
        !           507:
        !           508:        if (!ALTQ_IS_ENABLED(ifq))
        !           509:                /* cbq must have been detached */
        !           510:                return;
        !           511:
        !           512:        if ((cbqp = (cbq_state_t *)ifq->altq_disc) == NULL)
        !           513:                /* should not happen */
        !           514:                return;
        !           515:
        !           516:        ifp = ifq->altq_ifp;
        !           517:        if (ifp->if_start &&
        !           518:            cbqp->cbq_qlen > 0 && (ifp->if_flags & IFF_OACTIVE) == 0)
        !           519:                (*ifp->if_start)(ifp);
        !           520: }
        !           521:
        !           522: static void cbq_purge(cbq_state_t *cbqp)
        !           523: {
        !           524:        struct rm_class *cl;
        !           525:        int              i;
        !           526:
        !           527:        for (i = 0; i < CBQ_MAX_CLASSES; i++)
        !           528:                if ((cl = cbqp->cbq_class_tbl[i]) != NULL)
        !           529:                        rmc_dropall(cl);
        !           530:        if (ALTQ_IS_ENABLED(cbqp->ifnp.ifq_))
        !           531:                cbqp->ifnp.ifq_->ifq_len = 0;
        !           532: }

CVSweb