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

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

1.1     ! nbrk        1: /*     $OpenBSD: altq_red.c,v 1.13 2007/05/28 17:16:38 henning Exp $   */
        !             2: /*     $KAME: altq_red.c,v 1.10 2002/04/03 05:38:51 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: /*
        !            31:  * Copyright (c) 1990-1994 Regents of the University of California.
        !            32:  * All rights reserved.
        !            33:  *
        !            34:  * Redistribution and use in source and binary forms, with or without
        !            35:  * modification, are permitted provided that the following conditions
        !            36:  * are met:
        !            37:  * 1. Redistributions of source code must retain the above copyright
        !            38:  *    notice, this list of conditions and the following disclaimer.
        !            39:  * 2. Redistributions in binary form must reproduce the above copyright
        !            40:  *    notice, this list of conditions and the following disclaimer in the
        !            41:  *    documentation and/or other materials provided with the distribution.
        !            42:  * 3. All advertising materials mentioning features or use of this software
        !            43:  *    must display the following acknowledgement:
        !            44:  *     This product includes software developed by the Computer Systems
        !            45:  *     Engineering Group at Lawrence Berkeley Laboratory.
        !            46:  * 4. Neither the name of the University nor of the Laboratory may be used
        !            47:  *    to endorse or promote products derived from this software without
        !            48:  *    specific prior written permission.
        !            49:  *
        !            50:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            51:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            52:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            53:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            54:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            55:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            56:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            57:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            58:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            59:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            60:  * SUCH DAMAGE.
        !            61:  */
        !            62:
        !            63: #include <sys/param.h>
        !            64: #include <sys/malloc.h>
        !            65: #include <sys/mbuf.h>
        !            66: #include <sys/socket.h>
        !            67: #include <sys/systm.h>
        !            68: #include <sys/errno.h>
        !            69:
        !            70: #include <net/if.h>
        !            71: #include <net/if_types.h>
        !            72:
        !            73: #include <netinet/in.h>
        !            74: #include <netinet/in_systm.h>
        !            75: #include <netinet/ip.h>
        !            76: #ifdef INET6
        !            77: #include <netinet/ip6.h>
        !            78: #endif
        !            79:
        !            80: #include <net/pfvar.h>
        !            81: #include <altq/altq.h>
        !            82: #include <altq/altq_red.h>
        !            83:
        !            84: /*
        !            85:  * ALTQ/RED (Random Early Detection) implementation using 32-bit
        !            86:  * fixed-point calculation.
        !            87:  *
        !            88:  * written by kjc using the ns code as a reference.
        !            89:  * you can learn more about red and ns from Sally's home page at
        !            90:  * http://www-nrg.ee.lbl.gov/floyd/
        !            91:  *
        !            92:  * most of the red parameter values are fixed in this implementation
        !            93:  * to prevent fixed-point overflow/underflow.
        !            94:  * if you change the parameters, watch out for overflow/underflow!
        !            95:  *
        !            96:  * the parameters used are recommended values by Sally.
        !            97:  * the corresponding ns config looks:
        !            98:  *     q_weight=0.00195
        !            99:  *     minthresh=5 maxthresh=15 queue-size=60
        !           100:  *     linterm=30
        !           101:  *     dropmech=drop-tail
        !           102:  *     bytes=false (can't be handled by 32-bit fixed-point)
        !           103:  *     doubleq=false dqthresh=false
        !           104:  *     wait=true
        !           105:  */
        !           106: /*
        !           107:  * alternative red parameters for a slow link.
        !           108:  *
        !           109:  * assume the queue length becomes from zero to L and keeps L, it takes
        !           110:  * N packets for q_avg to reach 63% of L.
        !           111:  * when q_weight is 0.002, N is about 500 packets.
        !           112:  * for a slow link like dial-up, 500 packets takes more than 1 minute!
        !           113:  * when q_weight is 0.008, N is about 127 packets.
        !           114:  * when q_weight is 0.016, N is about 63 packets.
        !           115:  * bursts of 50 packets are allowed for 0.002, bursts of 25 packets
        !           116:  * are allowed for 0.016.
        !           117:  * see Sally's paper for more details.
        !           118:  */
        !           119: /* normal red parameters */
        !           120: #define        W_WEIGHT        512     /* inverse of weight of EWMA (511/512) */
        !           121:                                /* q_weight = 0.00195 */
        !           122:
        !           123: /* red parameters for a slow link */
        !           124: #define        W_WEIGHT_1      128     /* inverse of weight of EWMA (127/128) */
        !           125:                                /* q_weight = 0.0078125 */
        !           126:
        !           127: /* red parameters for a very slow link (e.g., dialup) */
        !           128: #define        W_WEIGHT_2      64      /* inverse of weight of EWMA (63/64) */
        !           129:                                /* q_weight = 0.015625 */
        !           130:
        !           131: /* fixed-point uses 12-bit decimal places */
        !           132: #define        FP_SHIFT        12      /* fixed-point shift */
        !           133:
        !           134: /* red parameters for drop probability */
        !           135: #define        INV_P_MAX       10      /* inverse of max drop probability */
        !           136: #define        TH_MIN          5       /* min threshold */
        !           137: #define        TH_MAX          15      /* max threshold */
        !           138:
        !           139: #define        RED_LIMIT       60      /* default max queue length */
        !           140: #define        RED_STATS               /* collect statistics */
        !           141:
        !           142: /*
        !           143:  * our default policy for forced-drop is drop-tail.
        !           144:  * (in altq-1.1.2 or earlier, the default was random-drop.
        !           145:  * but it makes more sense to punish the cause of the surge.)
        !           146:  * to switch to the random-drop policy, define "RED_RANDOM_DROP".
        !           147:  */
        !           148:
        !           149: /* default red parameter values */
        !           150: static int default_th_min = TH_MIN;
        !           151: static int default_th_max = TH_MAX;
        !           152: static int default_inv_pmax = INV_P_MAX;
        !           153:
        !           154: /*
        !           155:  * red support routines
        !           156:  */
        !           157: red_t *
        !           158: red_alloc(int weight, int inv_pmax, int th_min, int th_max, int flags,
        !           159:    int pkttime)
        !           160: {
        !           161:        red_t   *rp;
        !           162:        int      w, i;
        !           163:        int      npkts_per_sec;
        !           164:
        !           165:        MALLOC(rp, red_t *, sizeof(red_t), M_DEVBUF, M_WAITOK);
        !           166:        if (rp == NULL)
        !           167:                return (NULL);
        !           168:        bzero(rp, sizeof(red_t));
        !           169:
        !           170:        rp->red_avg = 0;
        !           171:        rp->red_idle = 1;
        !           172:
        !           173:        if (weight == 0)
        !           174:                rp->red_weight = W_WEIGHT;
        !           175:        else
        !           176:                rp->red_weight = weight;
        !           177:        if (inv_pmax == 0)
        !           178:                rp->red_inv_pmax = default_inv_pmax;
        !           179:        else
        !           180:                rp->red_inv_pmax = inv_pmax;
        !           181:        if (th_min == 0)
        !           182:                rp->red_thmin = default_th_min;
        !           183:        else
        !           184:                rp->red_thmin = th_min;
        !           185:        if (th_max == 0)
        !           186:                rp->red_thmax = default_th_max;
        !           187:        else
        !           188:                rp->red_thmax = th_max;
        !           189:
        !           190:        rp->red_flags = flags;
        !           191:
        !           192:        if (pkttime == 0)
        !           193:                /* default packet time: 1000 bytes / 10Mbps * 8 * 1000000 */
        !           194:                rp->red_pkttime = 800;
        !           195:        else
        !           196:                rp->red_pkttime = pkttime;
        !           197:
        !           198:        if (weight == 0) {
        !           199:                /* when the link is very slow, adjust red parameters */
        !           200:                npkts_per_sec = 1000000 / rp->red_pkttime;
        !           201:                if (npkts_per_sec < 50) {
        !           202:                        /* up to about 400Kbps */
        !           203:                        rp->red_weight = W_WEIGHT_2;
        !           204:                } else if (npkts_per_sec < 300) {
        !           205:                        /* up to about 2.4Mbps */
        !           206:                        rp->red_weight = W_WEIGHT_1;
        !           207:                }
        !           208:        }
        !           209:
        !           210:        /* calculate wshift.  weight must be power of 2 */
        !           211:        w = rp->red_weight;
        !           212:        for (i = 0; w > 1; i++)
        !           213:                w = w >> 1;
        !           214:        rp->red_wshift = i;
        !           215:        w = 1 << rp->red_wshift;
        !           216:        if (w != rp->red_weight) {
        !           217:                printf("invalid weight value %d for red! use %d\n",
        !           218:                       rp->red_weight, w);
        !           219:                rp->red_weight = w;
        !           220:        }
        !           221:
        !           222:        /*
        !           223:         * thmin_s and thmax_s are scaled versions of th_min and th_max
        !           224:         * to be compared with avg.
        !           225:         */
        !           226:        rp->red_thmin_s = rp->red_thmin << (rp->red_wshift + FP_SHIFT);
        !           227:        rp->red_thmax_s = rp->red_thmax << (rp->red_wshift + FP_SHIFT);
        !           228:
        !           229:        /*
        !           230:         * precompute probability denominator
        !           231:         *  probd = (2 * (TH_MAX-TH_MIN) / pmax) in fixed-point
        !           232:         */
        !           233:        rp->red_probd = (2 * (rp->red_thmax - rp->red_thmin)
        !           234:                         * rp->red_inv_pmax) << FP_SHIFT;
        !           235:
        !           236:        /* allocate weight table */
        !           237:        rp->red_wtab = wtab_alloc(rp->red_weight);
        !           238:
        !           239:        microtime(&rp->red_last);
        !           240:        return (rp);
        !           241: }
        !           242:
        !           243: void
        !           244: red_destroy(red_t *rp)
        !           245: {
        !           246:        wtab_destroy(rp->red_wtab);
        !           247:        FREE(rp, M_DEVBUF);
        !           248: }
        !           249:
        !           250: void
        !           251: red_getstats(red_t *rp, struct redstats *sp)
        !           252: {
        !           253:        sp->q_avg               = rp->red_avg >> rp->red_wshift;
        !           254:        sp->xmit_cnt            = rp->red_stats.xmit_cnt;
        !           255:        sp->drop_cnt            = rp->red_stats.drop_cnt;
        !           256:        sp->drop_forced         = rp->red_stats.drop_forced;
        !           257:        sp->drop_unforced       = rp->red_stats.drop_unforced;
        !           258:        sp->marked_packets      = rp->red_stats.marked_packets;
        !           259: }
        !           260:
        !           261: int
        !           262: red_addq(red_t *rp, class_queue_t *q, struct mbuf *m,
        !           263:     struct altq_pktattr *pktattr)
        !           264: {
        !           265:        int avg, droptype;
        !           266:        int n;
        !           267:
        !           268:        avg = rp->red_avg;
        !           269:
        !           270:        /*
        !           271:         * if we were idle, we pretend that n packets arrived during
        !           272:         * the idle period.
        !           273:         */
        !           274:        if (rp->red_idle) {
        !           275:                struct timeval now;
        !           276:                int t;
        !           277:
        !           278:                rp->red_idle = 0;
        !           279:                microtime(&now);
        !           280:                t = (now.tv_sec - rp->red_last.tv_sec);
        !           281:                if (t > 60) {
        !           282:                        /*
        !           283:                         * being idle for more than 1 minute, set avg to zero.
        !           284:                         * this prevents t from overflow.
        !           285:                         */
        !           286:                        avg = 0;
        !           287:                } else {
        !           288:                        t = t * 1000000 + (now.tv_usec - rp->red_last.tv_usec);
        !           289:                        n = t / rp->red_pkttime - 1;
        !           290:
        !           291:                        /* the following line does (avg = (1 - Wq)^n * avg) */
        !           292:                        if (n > 0)
        !           293:                                avg = (avg >> FP_SHIFT) *
        !           294:                                    pow_w(rp->red_wtab, n);
        !           295:                }
        !           296:        }
        !           297:
        !           298:        /* run estimator. (note: avg is scaled by WEIGHT in fixed-point) */
        !           299:        avg += (qlen(q) << FP_SHIFT) - (avg >> rp->red_wshift);
        !           300:        rp->red_avg = avg;              /* save the new value */
        !           301:
        !           302:        /*
        !           303:         * red_count keeps a tally of arriving traffic that has not
        !           304:         * been dropped.
        !           305:         */
        !           306:        rp->red_count++;
        !           307:
        !           308:        /* see if we drop early */
        !           309:        droptype = DTYPE_NODROP;
        !           310:        if (avg >= rp->red_thmin_s && qlen(q) > 1) {
        !           311:                if (avg >= rp->red_thmax_s) {
        !           312:                        /* avg >= th_max: forced drop */
        !           313:                        droptype = DTYPE_FORCED;
        !           314:                } else if (rp->red_old == 0) {
        !           315:                        /* first exceeds th_min */
        !           316:                        rp->red_count = 1;
        !           317:                        rp->red_old = 1;
        !           318:                } else if (drop_early((avg - rp->red_thmin_s) >> rp->red_wshift,
        !           319:                                      rp->red_probd, rp->red_count)) {
        !           320:                        /* mark or drop by red */
        !           321:                        if ((rp->red_flags & REDF_ECN) &&
        !           322:                            mark_ecn(m, pktattr, rp->red_flags)) {
        !           323:                                /* successfully marked.  do not drop. */
        !           324:                                rp->red_count = 0;
        !           325: #ifdef RED_STATS
        !           326:                                rp->red_stats.marked_packets++;
        !           327: #endif
        !           328:                        } else {
        !           329:                                /* unforced drop by red */
        !           330:                                droptype = DTYPE_EARLY;
        !           331:                        }
        !           332:                }
        !           333:        } else {
        !           334:                /* avg < th_min */
        !           335:                rp->red_old = 0;
        !           336:        }
        !           337:
        !           338:        /*
        !           339:         * if the queue length hits the hard limit, it's a forced drop.
        !           340:         */
        !           341:        if (droptype == DTYPE_NODROP && qlen(q) >= qlimit(q))
        !           342:                droptype = DTYPE_FORCED;
        !           343:
        !           344: #ifdef RED_RANDOM_DROP
        !           345:        /* if successful or forced drop, enqueue this packet. */
        !           346:        if (droptype != DTYPE_EARLY)
        !           347:                _addq(q, m);
        !           348: #else
        !           349:        /* if successful, enqueue this packet. */
        !           350:        if (droptype == DTYPE_NODROP)
        !           351:                _addq(q, m);
        !           352: #endif
        !           353:        if (droptype != DTYPE_NODROP) {
        !           354:                if (droptype == DTYPE_EARLY) {
        !           355:                        /* drop the incoming packet */
        !           356: #ifdef RED_STATS
        !           357:                        rp->red_stats.drop_unforced++;
        !           358: #endif
        !           359:                } else {
        !           360:                        /* forced drop, select a victim packet in the queue. */
        !           361: #ifdef RED_RANDOM_DROP
        !           362:                        m = _getq_random(q);
        !           363: #endif
        !           364: #ifdef RED_STATS
        !           365:                        rp->red_stats.drop_forced++;
        !           366: #endif
        !           367:                }
        !           368: #ifdef RED_STATS
        !           369:                PKTCNTR_ADD(&rp->red_stats.drop_cnt, m_pktlen(m));
        !           370: #endif
        !           371:                rp->red_count = 0;
        !           372:                m_freem(m);
        !           373:                return (-1);
        !           374:        }
        !           375:        /* successfully queued */
        !           376: #ifdef RED_STATS
        !           377:        PKTCNTR_ADD(&rp->red_stats.xmit_cnt, m_pktlen(m));
        !           378: #endif
        !           379:        return (0);
        !           380: }
        !           381:
        !           382: /*
        !           383:  * early-drop probability is calculated as follows:
        !           384:  *   prob = p_max * (avg - th_min) / (th_max - th_min)
        !           385:  *   prob_a = prob / (2 - count*prob)
        !           386:  *         = (avg-th_min) / (2*(th_max-th_min)*inv_p_max - count*(avg-th_min))
        !           387:  * here prob_a increases as successive undrop count increases.
        !           388:  * (prob_a starts from prob/2, becomes prob when (count == (1 / prob)),
        !           389:  * becomes 1 when (count >= (2 / prob))).
        !           390:  */
        !           391: int
        !           392: drop_early(int fp_len, int fp_probd, int count)
        !           393: {
        !           394:        int     d;              /* denominator of drop-probability */
        !           395:
        !           396:        d = fp_probd - count * fp_len;
        !           397:        if (d <= 0)
        !           398:                /* count exceeds the hard limit: drop or mark */
        !           399:                return (1);
        !           400:
        !           401:        /*
        !           402:         * now the range of d is [1..600] in fixed-point. (when
        !           403:         * th_max-th_min=10 and p_max=1/30)
        !           404:         * drop probability = (avg - TH_MIN) / d
        !           405:         */
        !           406:
        !           407:        if ((random() % d) < fp_len) {
        !           408:                /* drop or mark */
        !           409:                return (1);
        !           410:        }
        !           411:        /* no drop/mark */
        !           412:        return (0);
        !           413: }
        !           414:
        !           415: /*
        !           416:  * try to mark CE bit to the packet.
        !           417:  *    returns 1 if successfully marked, 0 otherwise.
        !           418:  */
        !           419: int
        !           420: mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags)
        !           421: {
        !           422:        struct mbuf     *m0;
        !           423:        void            *hdr;
        !           424:
        !           425:        hdr = m->m_pkthdr.pf.hdr;
        !           426:
        !           427:        /* verify that pattr_hdr is within the mbuf data */
        !           428:        for (m0 = m; m0 != NULL; m0 = m0->m_next)
        !           429:                if (((caddr_t)(hdr) >= m0->m_data) &&
        !           430:                    ((caddr_t)(hdr) < m0->m_data + m0->m_len))
        !           431:                        break;
        !           432:        if (m0 == NULL) {
        !           433:                /* ick, tag info is stale */
        !           434:                return (0);
        !           435:        }
        !           436:
        !           437:        switch (((struct ip *)hdr)->ip_v) {
        !           438:        case 4:
        !           439:                if (flags & REDF_ECN4) {
        !           440:                        struct ip *ip = hdr;
        !           441:                        u_int8_t otos;
        !           442:                        int sum;
        !           443:
        !           444:                        if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
        !           445:                                return (0);     /* not-ECT */
        !           446:                        if ((ip->ip_tos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
        !           447:                                return (1);     /* already marked */
        !           448:
        !           449:                        /*
        !           450:                         * ecn-capable but not marked,
        !           451:                         * mark CE and update checksum
        !           452:                         */
        !           453:                        otos = ip->ip_tos;
        !           454:                        ip->ip_tos |= IPTOS_ECN_CE;
        !           455:                        /*
        !           456:                         * update checksum (from RFC1624)
        !           457:                         *         HC' = ~(~HC + ~m + m')
        !           458:                         */
        !           459:                        sum = ~ntohs(ip->ip_sum) & 0xffff;
        !           460:                        sum += (~otos & 0xffff) + ip->ip_tos;
        !           461:                        sum = (sum >> 16) + (sum & 0xffff);
        !           462:                        sum += (sum >> 16);  /* add carry */
        !           463:                        ip->ip_sum = htons(~sum & 0xffff);
        !           464:                        return (1);
        !           465:                }
        !           466:                break;
        !           467: #ifdef INET6
        !           468:        case 6:
        !           469:                if (flags & REDF_ECN6) {
        !           470:                        struct ip6_hdr *ip6 = hdr;
        !           471:                        u_int32_t flowlabel;
        !           472:
        !           473:                        flowlabel = ntohl(ip6->ip6_flow);
        !           474:                        if ((flowlabel >> 28) != 6)
        !           475:                                return (0);     /* version mismatch! */
        !           476:                        if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
        !           477:                            (IPTOS_ECN_NOTECT << 20))
        !           478:                                return (0);     /* not-ECT */
        !           479:                        if ((flowlabel & (IPTOS_ECN_MASK << 20)) ==
        !           480:                            (IPTOS_ECN_CE << 20))
        !           481:                                return (1);     /* already marked */
        !           482:                        /*
        !           483:                         * ecn-capable but not marked,  mark CE
        !           484:                         */
        !           485:                        flowlabel |= (IPTOS_ECN_CE << 20);
        !           486:                        ip6->ip6_flow = htonl(flowlabel);
        !           487:                        return (1);
        !           488:                }
        !           489:                break;
        !           490: #endif  /* INET6 */
        !           491:        }
        !           492:
        !           493:        /* not marked */
        !           494:        return (0);
        !           495: }
        !           496:
        !           497: struct mbuf *
        !           498: red_getq(rp, q)
        !           499:        red_t *rp;
        !           500:        class_queue_t *q;
        !           501: {
        !           502:        struct mbuf *m;
        !           503:
        !           504:        if ((m = _getq(q)) == NULL) {
        !           505:                if (rp->red_idle == 0) {
        !           506:                        rp->red_idle = 1;
        !           507:                        microtime(&rp->red_last);
        !           508:                }
        !           509:                return NULL;
        !           510:        }
        !           511:
        !           512:        rp->red_idle = 0;
        !           513:        return (m);
        !           514: }
        !           515:
        !           516: /*
        !           517:  * helper routine to calibrate avg during idle.
        !           518:  * pow_w(wtab, n) returns (1 - Wq)^n in fixed-point
        !           519:  * here Wq = 1/weight and the code assumes Wq is close to zero.
        !           520:  *
        !           521:  * w_tab[n] holds ((1 - Wq)^(2^n)) in fixed-point.
        !           522:  */
        !           523: static struct wtab *wtab_list = NULL;  /* pointer to wtab list */
        !           524:
        !           525: struct wtab *
        !           526: wtab_alloc(int weight)
        !           527: {
        !           528:        struct wtab     *w;
        !           529:        int              i;
        !           530:
        !           531:        for (w = wtab_list; w != NULL; w = w->w_next)
        !           532:                if (w->w_weight == weight) {
        !           533:                        w->w_refcount++;
        !           534:                        return (w);
        !           535:                }
        !           536:
        !           537:        MALLOC(w, struct wtab *, sizeof(struct wtab), M_DEVBUF, M_WAITOK);
        !           538:        if (w == NULL)
        !           539:                panic("wtab_alloc: malloc failed!");
        !           540:        bzero(w, sizeof(struct wtab));
        !           541:        w->w_weight = weight;
        !           542:        w->w_refcount = 1;
        !           543:        w->w_next = wtab_list;
        !           544:        wtab_list = w;
        !           545:
        !           546:        /* initialize the weight table */
        !           547:        w->w_tab[0] = ((weight - 1) << FP_SHIFT) / weight;
        !           548:        for (i = 1; i < 32; i++) {
        !           549:                w->w_tab[i] = (w->w_tab[i-1] * w->w_tab[i-1]) >> FP_SHIFT;
        !           550:                if (w->w_tab[i] == 0 && w->w_param_max == 0)
        !           551:                        w->w_param_max = 1 << i;
        !           552:        }
        !           553:
        !           554:        return (w);
        !           555: }
        !           556:
        !           557: int
        !           558: wtab_destroy(struct wtab *w)
        !           559: {
        !           560:        struct wtab     *prev;
        !           561:
        !           562:        if (--w->w_refcount > 0)
        !           563:                return (0);
        !           564:
        !           565:        if (wtab_list == w)
        !           566:                wtab_list = w->w_next;
        !           567:        else for (prev = wtab_list; prev->w_next != NULL; prev = prev->w_next)
        !           568:                if (prev->w_next == w) {
        !           569:                        prev->w_next = w->w_next;
        !           570:                        break;
        !           571:                }
        !           572:
        !           573:        FREE(w, M_DEVBUF);
        !           574:        return (0);
        !           575: }
        !           576:
        !           577: int32_t
        !           578: pow_w(struct wtab *w, int n)
        !           579: {
        !           580:        int     i, bit;
        !           581:        int32_t val;
        !           582:
        !           583:        if (n >= w->w_param_max)
        !           584:                return (0);
        !           585:
        !           586:        val = 1 << FP_SHIFT;
        !           587:        if (n <= 0)
        !           588:                return (val);
        !           589:
        !           590:        bit = 1;
        !           591:        i = 0;
        !           592:        while (n) {
        !           593:                if (n & bit) {
        !           594:                        val = (val * w->w_tab[i]) >> FP_SHIFT;
        !           595:                        n &= ~bit;
        !           596:                }
        !           597:                i++;
        !           598:                bit <<=  1;
        !           599:        }
        !           600:        return (val);
        !           601: }

CVSweb