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

Annotation of sys/altq/altq_subr.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: altq_subr.c,v 1.21 2006/12/20 17:50:40 gwk Exp $      */
                      2: /*     $KAME: altq_subr.c,v 1.11 2002/01/11 08:11:49 kjc Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (C) 1997-2002
                      6:  *     Sony Computer Science Laboratories Inc.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: #include <sys/param.h>
                     31: #include <sys/malloc.h>
                     32: #include <sys/mbuf.h>
                     33: #include <sys/systm.h>
                     34: #include <sys/proc.h>
                     35: #include <sys/socket.h>
                     36: #include <sys/socketvar.h>
                     37: #include <sys/kernel.h>
                     38: #include <sys/errno.h>
                     39: #include <sys/syslog.h>
                     40: #include <sys/sysctl.h>
                     41: #include <sys/queue.h>
                     42:
                     43: #include <net/if.h>
                     44: #include <net/if_dl.h>
                     45: #include <net/if_types.h>
                     46:
                     47: #include <netinet/in.h>
                     48: #include <netinet/in_systm.h>
                     49: #include <netinet/ip.h>
                     50: #ifdef INET6
                     51: #include <netinet/ip6.h>
                     52: #endif
                     53: #include <netinet/tcp.h>
                     54: #include <netinet/udp.h>
                     55:
                     56: #include <net/pfvar.h>
                     57: #include <altq/altq.h>
                     58:
                     59: /* machine dependent clock related includes */
                     60: #if defined(__i386__)
                     61: #include <machine/cpufunc.h>           /* for pentium tsc */
                     62: #include <machine/specialreg.h>                /* for CPUID_TSC */
                     63: #endif /* __i386__ */
                     64:
                     65: /*
                     66:  * internal function prototypes
                     67:  */
                     68: static void    tbr_timeout(void *);
                     69: int (*altq_input)(struct mbuf *, int) = NULL;
                     70: static int tbr_timer = 0;      /* token bucket regulator timer */
                     71: static struct callout tbr_callout = CALLOUT_INITIALIZER;
                     72:
                     73: /*
                     74:  * alternate queueing support routines
                     75:  */
                     76:
                     77: /* look up the queue state by the interface name and the queueing type. */
                     78: void *
                     79: altq_lookup(name, type)
                     80:        char *name;
                     81:        int type;
                     82: {
                     83:        struct ifnet *ifp;
                     84:
                     85:        if ((ifp = ifunit(name)) != NULL) {
                     86:                if (type != ALTQT_NONE && ifp->if_snd.altq_type == type)
                     87:                        return (ifp->if_snd.altq_disc);
                     88:        }
                     89:
                     90:        return NULL;
                     91: }
                     92:
                     93: int
                     94: altq_attach(ifq, type, discipline, enqueue, dequeue, request, clfier, classify)
                     95:        struct ifaltq *ifq;
                     96:        int type;
                     97:        void *discipline;
                     98:        int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
                     99:        struct mbuf *(*dequeue)(struct ifaltq *, int);
                    100:        int (*request)(struct ifaltq *, int, void *);
                    101:        void *clfier;
                    102:        void *(*classify)(void *, struct mbuf *, int);
                    103: {
                    104:        if (!ALTQ_IS_READY(ifq))
                    105:                return ENXIO;
                    106:
                    107: #if 0  /* pfaltq can override the existing discipline */
                    108:        if (ALTQ_IS_ENABLED(ifq))
                    109:                return EBUSY;
                    110:        if (ALTQ_IS_ATTACHED(ifq))
                    111:                return EEXIST;
                    112: #endif
                    113:        ifq->altq_type     = type;
                    114:        ifq->altq_disc     = discipline;
                    115:        ifq->altq_enqueue  = enqueue;
                    116:        ifq->altq_dequeue  = dequeue;
                    117:        ifq->altq_request  = request;
                    118:        ifq->altq_clfier   = clfier;
                    119:        ifq->altq_classify = classify;
                    120:        ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED);
                    121:
                    122:        return 0;
                    123: }
                    124:
                    125: int
                    126: altq_detach(ifq)
                    127:        struct ifaltq *ifq;
                    128: {
                    129:        if (!ALTQ_IS_READY(ifq))
                    130:                return ENXIO;
                    131:        if (ALTQ_IS_ENABLED(ifq))
                    132:                return EBUSY;
                    133:        if (!ALTQ_IS_ATTACHED(ifq))
                    134:                return (0);
                    135:
                    136:        ifq->altq_type     = ALTQT_NONE;
                    137:        ifq->altq_disc     = NULL;
                    138:        ifq->altq_enqueue  = NULL;
                    139:        ifq->altq_dequeue  = NULL;
                    140:        ifq->altq_request  = NULL;
                    141:        ifq->altq_clfier   = NULL;
                    142:        ifq->altq_classify = NULL;
                    143:        ifq->altq_flags &= ALTQF_CANTCHANGE;
                    144:        return 0;
                    145: }
                    146:
                    147: int
                    148: altq_enable(ifq)
                    149:        struct ifaltq *ifq;
                    150: {
                    151:        int s;
                    152:
                    153:        if (!ALTQ_IS_READY(ifq))
                    154:                return ENXIO;
                    155:        if (ALTQ_IS_ENABLED(ifq))
                    156:                return 0;
                    157:
                    158:        s = splnet();
                    159:        IFQ_PURGE(ifq);
                    160:        ASSERT(ifq->ifq_len == 0);
                    161:        ifq->altq_flags |= ALTQF_ENABLED;
                    162:        if (ifq->altq_clfier != NULL)
                    163:                ifq->altq_flags |= ALTQF_CLASSIFY;
                    164:        splx(s);
                    165:
                    166:        return 0;
                    167: }
                    168:
                    169: int
                    170: altq_disable(ifq)
                    171:        struct ifaltq *ifq;
                    172: {
                    173:        int s;
                    174:
                    175:        if (!ALTQ_IS_ENABLED(ifq))
                    176:                return 0;
                    177:
                    178:        s = splnet();
                    179:        IFQ_PURGE(ifq);
                    180:        ASSERT(ifq->ifq_len == 0);
                    181:        ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
                    182:        splx(s);
                    183:        return 0;
                    184: }
                    185:
                    186: void
                    187: altq_assert(file, line, failedexpr)
                    188:        const char *file, *failedexpr;
                    189:        int line;
                    190: {
                    191:        (void)printf("altq assertion \"%s\" failed: file \"%s\", line %d\n",
                    192:                     failedexpr, file, line);
                    193:        panic("altq assertion");
                    194:        /* NOTREACHED */
                    195: }
                    196:
                    197: /*
                    198:  * internal representation of token bucket parameters
                    199:  *     rate:   byte_per_unittime << 32
                    200:  *             (((bits_per_sec) / 8) << 32) / machclk_freq
                    201:  *     depth:  byte << 32
                    202:  *
                    203:  */
                    204: #define        TBR_SHIFT       32
                    205: #define        TBR_SCALE(x)    ((int64_t)(x) << TBR_SHIFT)
                    206: #define        TBR_UNSCALE(x)  ((x) >> TBR_SHIFT)
                    207:
                    208: struct mbuf *
                    209: tbr_dequeue(ifq, op)
                    210:        struct ifaltq *ifq;
                    211:        int op;
                    212: {
                    213:        struct tb_regulator *tbr;
                    214:        struct mbuf *m;
                    215:        int64_t interval;
                    216:        u_int64_t now;
                    217:
                    218:        tbr = ifq->altq_tbr;
                    219:        if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) {
                    220:                /* if this is a remove after poll, bypass tbr check */
                    221:        } else {
                    222:                /* update token only when it is negative */
                    223:                if (tbr->tbr_token <= 0) {
                    224:                        now = read_machclk();
                    225:                        interval = now - tbr->tbr_last;
                    226:                        if (interval >= tbr->tbr_filluptime)
                    227:                                tbr->tbr_token = tbr->tbr_depth;
                    228:                        else {
                    229:                                tbr->tbr_token += interval * tbr->tbr_rate;
                    230:                                if (tbr->tbr_token > tbr->tbr_depth)
                    231:                                        tbr->tbr_token = tbr->tbr_depth;
                    232:                        }
                    233:                        tbr->tbr_last = now;
                    234:                }
                    235:                /* if token is still negative, don't allow dequeue */
                    236:                if (tbr->tbr_token <= 0)
                    237:                        return (NULL);
                    238:        }
                    239:
                    240:        if (ALTQ_IS_ENABLED(ifq))
                    241:                m = (*ifq->altq_dequeue)(ifq, op);
                    242:        else {
                    243:                if (op == ALTDQ_POLL)
                    244:                        IF_POLL(ifq, m);
                    245:                else
                    246:                        IF_DEQUEUE(ifq, m);
                    247:        }
                    248:
                    249:        if (m != NULL && op == ALTDQ_REMOVE)
                    250:                tbr->tbr_token -= TBR_SCALE(m_pktlen(m));
                    251:        tbr->tbr_lastop = op;
                    252:        return (m);
                    253: }
                    254:
                    255: /*
                    256:  * set a token bucket regulator.
                    257:  * if the specified rate is zero, the token bucket regulator is deleted.
                    258:  */
                    259: int
                    260: tbr_set(ifq, profile)
                    261:        struct ifaltq *ifq;
                    262:        struct tb_profile *profile;
                    263: {
                    264:        struct tb_regulator *tbr, *otbr;
                    265:
                    266:        if (machclk_freq == 0)
                    267:                init_machclk();
                    268:        if (machclk_freq == 0) {
                    269:                printf("tbr_set: no cpu clock available!\n");
                    270:                return (ENXIO);
                    271:        }
                    272:
                    273:        if (profile->rate == 0) {
                    274:                /* delete this tbr */
                    275:                if ((tbr = ifq->altq_tbr) == NULL)
                    276:                        return (ENOENT);
                    277:                ifq->altq_tbr = NULL;
                    278:                FREE(tbr, M_DEVBUF);
                    279:                return (0);
                    280:        }
                    281:
                    282:        MALLOC(tbr, struct tb_regulator *, sizeof(struct tb_regulator),
                    283:               M_DEVBUF, M_WAITOK);
                    284:        if (tbr == NULL)
                    285:                return (ENOMEM);
                    286:        bzero(tbr, sizeof(struct tb_regulator));
                    287:
                    288:        tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq;
                    289:        tbr->tbr_depth = TBR_SCALE(profile->depth);
                    290:        if (tbr->tbr_rate > 0)
                    291:                tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
                    292:        else
                    293:                tbr->tbr_filluptime = 0xffffffffffffffffLL;
                    294:        tbr->tbr_token = tbr->tbr_depth;
                    295:        tbr->tbr_last = read_machclk();
                    296:        tbr->tbr_lastop = ALTDQ_REMOVE;
                    297:
                    298:        otbr = ifq->altq_tbr;
                    299:        ifq->altq_tbr = tbr;    /* set the new tbr */
                    300:
                    301:        if (otbr != NULL)
                    302:                FREE(otbr, M_DEVBUF);
                    303:        else {
                    304:                if (tbr_timer == 0) {
                    305:                        CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
                    306:                        tbr_timer = 1;
                    307:                }
                    308:        }
                    309:        return (0);
                    310: }
                    311:
                    312: /*
                    313:  * tbr_timeout goes through the interface list, and kicks the drivers
                    314:  * if necessary.
                    315:  */
                    316: static void
                    317: tbr_timeout(arg)
                    318:        void *arg;
                    319: {
                    320:        struct ifnet *ifp;
                    321:        int active, s;
                    322:
                    323:        active = 0;
                    324:        s = splnet();
                    325:        for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
                    326:                if (!TBR_IS_ENABLED(&ifp->if_snd))
                    327:                        continue;
                    328:                active++;
                    329:                if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL)
                    330:                        (*ifp->if_start)(ifp);
                    331:        }
                    332:        splx(s);
                    333:        if (active > 0)
                    334:                CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0);
                    335:        else
                    336:                tbr_timer = 0;  /* don't need tbr_timer anymore */
                    337: #if defined(__alpha__) && !defined(ALTQ_NOPCC)
                    338:        {
                    339:                /*
                    340:                 * XXX read out the machine dependent clock once a second
                    341:                 * to detect counter wrap-around.
                    342:                 */
                    343:                static u_int cnt;
                    344:
                    345:                if (++cnt >= hz) {
                    346:                        (void)read_machclk();
                    347:                        cnt = 0;
                    348:                }
                    349:        }
                    350: #endif /* __alpha__ && !ALTQ_NOPCC */
                    351: }
                    352:
                    353: /*
                    354:  * get token bucket regulator profile
                    355:  */
                    356: int
                    357: tbr_get(ifq, profile)
                    358:        struct ifaltq *ifq;
                    359:        struct tb_profile *profile;
                    360: {
                    361:        struct tb_regulator *tbr;
                    362:
                    363:        if ((tbr = ifq->altq_tbr) == NULL) {
                    364:                profile->rate = 0;
                    365:                profile->depth = 0;
                    366:        } else {
                    367:                profile->rate =
                    368:                    (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
                    369:                profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
                    370:        }
                    371:        return (0);
                    372: }
                    373:
                    374: /*
                    375:  * attach a discipline to the interface.  if one already exists, it is
                    376:  * overridden.
                    377:  */
                    378: int
                    379: altq_pfattach(struct pf_altq *a)
                    380: {
                    381:        int error = 0;
                    382:
                    383:        switch (a->scheduler) {
                    384:        case ALTQT_NONE:
                    385:                break;
                    386: #ifdef ALTQ_CBQ
                    387:        case ALTQT_CBQ:
                    388:                error = cbq_pfattach(a);
                    389:                break;
                    390: #endif
                    391: #ifdef ALTQ_PRIQ
                    392:        case ALTQT_PRIQ:
                    393:                error = priq_pfattach(a);
                    394:                break;
                    395: #endif
                    396: #ifdef ALTQ_HFSC
                    397:        case ALTQT_HFSC:
                    398:                error = hfsc_pfattach(a);
                    399:                break;
                    400: #endif
                    401:        default:
                    402:                error = ENXIO;
                    403:        }
                    404:
                    405:        return (error);
                    406: }
                    407:
                    408: /*
                    409:  * detach a discipline from the interface.
                    410:  * it is possible that the discipline was already overridden by another
                    411:  * discipline.
                    412:  */
                    413: int
                    414: altq_pfdetach(struct pf_altq *a)
                    415: {
                    416:        struct ifnet *ifp;
                    417:        int s, error = 0;
                    418:
                    419:        if ((ifp = ifunit(a->ifname)) == NULL)
                    420:                return (EINVAL);
                    421:
                    422:        /* if this discipline is no longer referenced, just return */
                    423:        if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc)
                    424:                return (0);
                    425:
                    426:        s = splnet();
                    427:        if (ALTQ_IS_ENABLED(&ifp->if_snd))
                    428:                error = altq_disable(&ifp->if_snd);
                    429:        if (error == 0)
                    430:                error = altq_detach(&ifp->if_snd);
                    431:        splx(s);
                    432:
                    433:        return (error);
                    434: }
                    435:
                    436: /*
                    437:  * add a discipline or a queue
                    438:  */
                    439: int
                    440: altq_add(struct pf_altq *a)
                    441: {
                    442:        int error = 0;
                    443:
                    444:        if (a->qname[0] != 0)
                    445:                return (altq_add_queue(a));
                    446:
                    447:        if (machclk_freq == 0)
                    448:                init_machclk();
                    449:        if (machclk_freq == 0)
                    450:                panic("altq_add: no cpu clock");
                    451:
                    452:        switch (a->scheduler) {
                    453: #ifdef ALTQ_CBQ
                    454:        case ALTQT_CBQ:
                    455:                error = cbq_add_altq(a);
                    456:                break;
                    457: #endif
                    458: #ifdef ALTQ_PRIQ
                    459:        case ALTQT_PRIQ:
                    460:                error = priq_add_altq(a);
                    461:                break;
                    462: #endif
                    463: #ifdef ALTQ_HFSC
                    464:        case ALTQT_HFSC:
                    465:                error = hfsc_add_altq(a);
                    466:                break;
                    467: #endif
                    468:        default:
                    469:                error = ENXIO;
                    470:        }
                    471:
                    472:        return (error);
                    473: }
                    474:
                    475: /*
                    476:  * remove a discipline or a queue
                    477:  */
                    478: int
                    479: altq_remove(struct pf_altq *a)
                    480: {
                    481:        int error = 0;
                    482:
                    483:        if (a->qname[0] != 0)
                    484:                return (altq_remove_queue(a));
                    485:
                    486:        switch (a->scheduler) {
                    487: #ifdef ALTQ_CBQ
                    488:        case ALTQT_CBQ:
                    489:                error = cbq_remove_altq(a);
                    490:                break;
                    491: #endif
                    492: #ifdef ALTQ_PRIQ
                    493:        case ALTQT_PRIQ:
                    494:                error = priq_remove_altq(a);
                    495:                break;
                    496: #endif
                    497: #ifdef ALTQ_HFSC
                    498:        case ALTQT_HFSC:
                    499:                error = hfsc_remove_altq(a);
                    500:                break;
                    501: #endif
                    502:        default:
                    503:                error = ENXIO;
                    504:        }
                    505:
                    506:        return (error);
                    507: }
                    508:
                    509: /*
                    510:  * add a queue to the discipline
                    511:  */
                    512: int
                    513: altq_add_queue(struct pf_altq *a)
                    514: {
                    515:        int error = 0;
                    516:
                    517:        switch (a->scheduler) {
                    518: #ifdef ALTQ_CBQ
                    519:        case ALTQT_CBQ:
                    520:                error = cbq_add_queue(a);
                    521:                break;
                    522: #endif
                    523: #ifdef ALTQ_PRIQ
                    524:        case ALTQT_PRIQ:
                    525:                error = priq_add_queue(a);
                    526:                break;
                    527: #endif
                    528: #ifdef ALTQ_HFSC
                    529:        case ALTQT_HFSC:
                    530:                error = hfsc_add_queue(a);
                    531:                break;
                    532: #endif
                    533:        default:
                    534:                error = ENXIO;
                    535:        }
                    536:
                    537:        return (error);
                    538: }
                    539:
                    540: /*
                    541:  * remove a queue from the discipline
                    542:  */
                    543: int
                    544: altq_remove_queue(struct pf_altq *a)
                    545: {
                    546:        int error = 0;
                    547:
                    548:        switch (a->scheduler) {
                    549: #ifdef ALTQ_CBQ
                    550:        case ALTQT_CBQ:
                    551:                error = cbq_remove_queue(a);
                    552:                break;
                    553: #endif
                    554: #ifdef ALTQ_PRIQ
                    555:        case ALTQT_PRIQ:
                    556:                error = priq_remove_queue(a);
                    557:                break;
                    558: #endif
                    559: #ifdef ALTQ_HFSC
                    560:        case ALTQT_HFSC:
                    561:                error = hfsc_remove_queue(a);
                    562:                break;
                    563: #endif
                    564:        default:
                    565:                error = ENXIO;
                    566:        }
                    567:
                    568:        return (error);
                    569: }
                    570:
                    571: /*
                    572:  * get queue statistics
                    573:  */
                    574: int
                    575: altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
                    576: {
                    577:        int error = 0;
                    578:
                    579:        switch (a->scheduler) {
                    580: #ifdef ALTQ_CBQ
                    581:        case ALTQT_CBQ:
                    582:                error = cbq_getqstats(a, ubuf, nbytes);
                    583:                break;
                    584: #endif
                    585: #ifdef ALTQ_PRIQ
                    586:        case ALTQT_PRIQ:
                    587:                error = priq_getqstats(a, ubuf, nbytes);
                    588:                break;
                    589: #endif
                    590: #ifdef ALTQ_HFSC
                    591:        case ALTQT_HFSC:
                    592:                error = hfsc_getqstats(a, ubuf, nbytes);
                    593:                break;
                    594: #endif
                    595:        default:
                    596:                error = ENXIO;
                    597:        }
                    598:
                    599:        return (error);
                    600: }
                    601:
                    602: /*
                    603:  * read and write diffserv field in IPv4 or IPv6 header
                    604:  */
                    605: u_int8_t
                    606: read_dsfield(m, pktattr)
                    607:        struct mbuf *m;
                    608:        struct altq_pktattr *pktattr;
                    609: {
                    610:        struct mbuf *m0;
                    611:        u_int8_t ds_field = 0;
                    612:
                    613:        if (pktattr == NULL ||
                    614:            (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
                    615:                return ((u_int8_t)0);
                    616:
                    617:        /* verify that pattr_hdr is within the mbuf data */
                    618:        for (m0 = m; m0 != NULL; m0 = m0->m_next)
                    619:                if ((pktattr->pattr_hdr >= m0->m_data) &&
                    620:                    (pktattr->pattr_hdr < m0->m_data + m0->m_len))
                    621:                        break;
                    622:        if (m0 == NULL) {
                    623:                /* ick, pattr_hdr is stale */
                    624:                pktattr->pattr_af = AF_UNSPEC;
                    625: #ifdef ALTQ_DEBUG
                    626:                printf("read_dsfield: can't locate header!\n");
                    627: #endif
                    628:                return ((u_int8_t)0);
                    629:        }
                    630:
                    631:        if (pktattr->pattr_af == AF_INET) {
                    632:                struct ip *ip = (struct ip *)pktattr->pattr_hdr;
                    633:
                    634:                if (ip->ip_v != 4)
                    635:                        return ((u_int8_t)0);   /* version mismatch! */
                    636:                ds_field = ip->ip_tos;
                    637:        }
                    638: #ifdef INET6
                    639:        else if (pktattr->pattr_af == AF_INET6) {
                    640:                struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
                    641:                u_int32_t flowlabel;
                    642:
                    643:                flowlabel = ntohl(ip6->ip6_flow);
                    644:                if ((flowlabel >> 28) != 6)
                    645:                        return ((u_int8_t)0);   /* version mismatch! */
                    646:                ds_field = (flowlabel >> 20) & 0xff;
                    647:        }
                    648: #endif
                    649:        return (ds_field);
                    650: }
                    651:
                    652: void
                    653: write_dsfield(m, pktattr, dsfield)
                    654:        struct mbuf *m;
                    655:        struct altq_pktattr *pktattr;
                    656:        u_int8_t dsfield;
                    657: {
                    658:        struct mbuf *m0;
                    659:
                    660:        if (pktattr == NULL ||
                    661:            (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
                    662:                return;
                    663:
                    664:        /* verify that pattr_hdr is within the mbuf data */
                    665:        for (m0 = m; m0 != NULL; m0 = m0->m_next)
                    666:                if ((pktattr->pattr_hdr >= m0->m_data) &&
                    667:                    (pktattr->pattr_hdr < m0->m_data + m0->m_len))
                    668:                        break;
                    669:        if (m0 == NULL) {
                    670:                /* ick, pattr_hdr is stale */
                    671:                pktattr->pattr_af = AF_UNSPEC;
                    672: #ifdef ALTQ_DEBUG
                    673:                printf("write_dsfield: can't locate header!\n");
                    674: #endif
                    675:                return;
                    676:        }
                    677:
                    678:        if (pktattr->pattr_af == AF_INET) {
                    679:                struct ip *ip = (struct ip *)pktattr->pattr_hdr;
                    680:                u_int8_t old;
                    681:                int32_t sum;
                    682:
                    683:                if (ip->ip_v != 4)
                    684:                        return;         /* version mismatch! */
                    685:                old = ip->ip_tos;
                    686:                dsfield |= old & 3;     /* leave CU bits */
                    687:                if (old == dsfield)
                    688:                        return;
                    689:                ip->ip_tos = dsfield;
                    690:                /*
                    691:                 * update checksum (from RFC1624)
                    692:                 *         HC' = ~(~HC + ~m + m')
                    693:                 */
                    694:                sum = ~ntohs(ip->ip_sum) & 0xffff;
                    695:                sum += 0xff00 + (~old & 0xff) + dsfield;
                    696:                sum = (sum >> 16) + (sum & 0xffff);
                    697:                sum += (sum >> 16);  /* add carry */
                    698:
                    699:                ip->ip_sum = htons(~sum & 0xffff);
                    700:        }
                    701: #ifdef INET6
                    702:        else if (pktattr->pattr_af == AF_INET6) {
                    703:                struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
                    704:                u_int32_t flowlabel;
                    705:
                    706:                flowlabel = ntohl(ip6->ip6_flow);
                    707:                if ((flowlabel >> 28) != 6)
                    708:                        return;         /* version mismatch! */
                    709:                flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
                    710:                ip6->ip6_flow = htonl(flowlabel);
                    711:        }
                    712: #endif
                    713:        return;
                    714: }
                    715:
                    716:
                    717: /*
                    718:  * high resolution clock support taking advantage of a machine dependent
                    719:  * high resolution time counter (e.g., timestamp counter of intel pentium).
                    720:  * we assume
                    721:  *  - 64-bit-long monotonically-increasing counter
                    722:  *  - frequency range is 100M-4GHz (CPU speed)
                    723:  */
                    724: /* if pcc is not available or disabled, emulate 256MHz using microtime() */
                    725: #define        MACHCLK_SHIFT   8
                    726:
                    727: int machclk_usepcc;
                    728: u_int32_t machclk_freq = 0;
                    729: u_int32_t machclk_per_tick = 0;
                    730:
                    731: #ifdef __alpha__
                    732: extern u_int64_t cycles_per_usec;      /* alpha cpu clock frequency */
                    733: #endif /* __alpha__ */
                    734:
                    735: void
                    736: init_machclk(void)
                    737: {
                    738:        machclk_usepcc = 1;
                    739:
                    740: #if (!defined(__i386__) && !defined(__alpha__)) || defined(ALTQ_NOPCC)
                    741:        machclk_usepcc = 0;
                    742: #endif
                    743: #if defined(__FreeBSD__) && defined(SMP)
                    744:        machclk_usepcc = 0;
                    745: #endif
                    746: #if defined(__NetBSD__) && defined(MULTIPROCESSOR)
                    747:        machclk_usepcc = 0;
                    748: #endif
                    749: #if defined(__OpenBSD__) && defined(__HAVE_TIMECOUNTER)
                    750:        /*
                    751:         * If we have timecounters, microtime is good enough and we can
                    752:         * avoid problems on machines with variable cycle counter
                    753:         * frequencies.
                    754:         */
                    755:        machclk_usepcc = 0;
                    756: #endif
                    757: #ifdef __i386__
                    758:        /* check if TSC is available */
                    759:        if (machclk_usepcc == 1 && (cpu_feature & CPUID_TSC) == 0)
                    760:                machclk_usepcc = 0;
                    761: #endif
                    762:
                    763:        if (machclk_usepcc == 0) {
                    764:                /* emulate 256MHz using microtime() */
                    765:                machclk_freq = 1000000 << MACHCLK_SHIFT;
                    766:                machclk_per_tick = machclk_freq / hz;
                    767: #ifdef ALTQ_DEBUG
                    768:                printf("altq: emulate %uHz cpu clock\n", machclk_freq);
                    769: #endif
                    770:                return;
                    771:        }
                    772:
                    773:        /*
                    774:         * if the clock frequency (of Pentium TSC or Alpha PCC) is
                    775:         * accessible, just use it.
                    776:         */
                    777: #if defined(__i386__) && (defined(I586_CPU) || defined(I686_CPU))
                    778:        /* XXX - this will break down with variable cpu frequency. */
                    779:        machclk_freq = cpuspeed * 1000000;
                    780: #endif
                    781: #if defined(__alpha__)
                    782:        machclk_freq = (u_int32_t)(cycles_per_usec * 1000000);
                    783: #endif /* __alpha__ */
                    784:
                    785:        /*
                    786:         * if we don't know the clock frequency, measure it.
                    787:         */
                    788:        if (machclk_freq == 0) {
                    789:                static int      wait;
                    790:                struct timeval  tv_start, tv_end;
                    791:                u_int64_t       start, end, diff;
                    792:                int             timo;
                    793:
                    794:                microtime(&tv_start);
                    795:                start = read_machclk();
                    796:                timo = hz;      /* 1 sec */
                    797:                (void)tsleep(&wait, PWAIT | PCATCH, "init_machclk", timo);
                    798:                microtime(&tv_end);
                    799:                end = read_machclk();
                    800:                diff = (u_int64_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000000
                    801:                    + tv_end.tv_usec - tv_start.tv_usec;
                    802:                if (diff != 0)
                    803:                        machclk_freq = (u_int)((end - start) * 1000000 / diff);
                    804:        }
                    805:
                    806:        machclk_per_tick = machclk_freq / hz;
                    807:
                    808: #ifdef ALTQ_DEBUG
                    809:        printf("altq: CPU clock: %uHz\n", machclk_freq);
                    810: #endif
                    811: }
                    812:
                    813: #if defined(__OpenBSD__) && defined(__i386__)
                    814: static __inline u_int64_t
                    815: rdtsc(void)
                    816: {
                    817:        u_int64_t rv;
                    818:        __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
                    819:        return (rv);
                    820: }
                    821: #endif /* __OpenBSD__ && __i386__ */
                    822:
                    823: u_int64_t
                    824: read_machclk(void)
                    825: {
                    826:        u_int64_t val;
                    827:
                    828:        if (machclk_usepcc) {
                    829: #if defined(__i386__)
                    830:                val = rdtsc();
                    831: #elif defined(__alpha__)
                    832:                static u_int32_t last_pcc, upper;
                    833:                u_int32_t pcc;
                    834:
                    835:                /*
                    836:                 * for alpha, make a 64bit counter value out of the 32bit
                    837:                 * alpha processor cycle counter.
                    838:                 * read_machclk must be called within a half of its
                    839:                 * wrap-around cycle (about 5 sec for 400MHz cpu) to properly
                    840:                 * detect a counter wrap-around.
                    841:                 * tbr_timeout calls read_machclk once a second.
                    842:                 */
                    843:                pcc = (u_int32_t)alpha_rpcc();
                    844:                if (pcc <= last_pcc)
                    845:                        upper++;
                    846:                last_pcc = pcc;
                    847:                val = ((u_int64_t)upper << 32) + pcc;
                    848: #else
                    849:                panic("read_machclk");
                    850: #endif
                    851:        } else {
                    852:                struct timeval tv;
                    853:
                    854:                microuptime(&tv);
                    855:                val = (((u_int64_t)(tv.tv_sec) * 1000000
                    856:                    + tv.tv_usec) << MACHCLK_SHIFT);
                    857:        }
                    858:        return (val);
                    859: }

CVSweb