[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

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