[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     ! 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