OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sched/] [sch_gred.c] - Diff between revs 1275 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1275 Rev 1765
/*
/*
 * net/sched/sch_gred.c Generic Random Early Detection queue.
 * net/sched/sch_gred.c Generic Random Early Detection queue.
 *
 *
 *
 *
 *              This program is free software; you can redistribute it and/or
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
 *              modify it under the terms of the GNU General Public License
 *              as published by the Free Software Foundation; either version
 *              as published by the Free Software Foundation; either version
 *              2 of the License, or (at your option) any later version.
 *              2 of the License, or (at your option) any later version.
 *
 *
 * Authors:    J Hadi Salim (hadi@cyberus.ca) 1998-2002
 * Authors:    J Hadi Salim (hadi@cyberus.ca) 1998-2002
 *
 *
 *             991129: -  Bug fix with grio mode
 *             991129: -  Bug fix with grio mode
 *                     - a better sing. AvgQ mode with Grio(WRED)
 *                     - a better sing. AvgQ mode with Grio(WRED)
 *                     - A finer grained VQ dequeue based on sugestion
 *                     - A finer grained VQ dequeue based on sugestion
 *                       from Ren Liu
 *                       from Ren Liu
 *                     - More error checks
 *                     - More error checks
 *
 *
 *
 *
 *
 *
 *  For all the glorious comments look at Alexey's sch_red.c
 *  For all the glorious comments look at Alexey's sch_red.c
 */
 */
 
 
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/etherdevice.h>
#include <linux/notifier.h>
#include <linux/notifier.h>
#include <net/ip.h>
#include <net/ip.h>
#include <net/route.h>
#include <net/route.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
#include <net/pkt_sched.h>
 
 
#if 1 /* control */
#if 1 /* control */
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
#else
#else
#define DPRINTK(format,args...)
#define DPRINTK(format,args...)
#endif
#endif
 
 
#if 0 /* data */
#if 0 /* data */
#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
#else
#else
#define D2PRINTK(format,args...)
#define D2PRINTK(format,args...)
#endif
#endif
 
 
struct gred_sched_data;
struct gred_sched_data;
struct gred_sched;
struct gred_sched;
 
 
struct gred_sched_data
struct gred_sched_data
{
{
/* Parameters */
/* Parameters */
        u32             limit;          /* HARD maximal queue length    */
        u32             limit;          /* HARD maximal queue length    */
        u32             qth_min;        /* Min average length threshold: A scaled */
        u32             qth_min;        /* Min average length threshold: A scaled */
        u32             qth_max;        /* Max average length threshold: A scaled */
        u32             qth_max;        /* Max average length threshold: A scaled */
        u32             DP;             /* the drop pramaters */
        u32             DP;             /* the drop pramaters */
        char            Wlog;           /* log(W)               */
        char            Wlog;           /* log(W)               */
        char            Plog;           /* random number bits   */
        char            Plog;           /* random number bits   */
        u32             Scell_max;
        u32             Scell_max;
        u32             Rmask;
        u32             Rmask;
        u32             bytesin;        /* bytes seen on virtualQ so far*/
        u32             bytesin;        /* bytes seen on virtualQ so far*/
        u32             packetsin;      /* packets seen on virtualQ so far*/
        u32             packetsin;      /* packets seen on virtualQ so far*/
        u32             backlog;        /* bytes on the virtualQ */
        u32             backlog;        /* bytes on the virtualQ */
        u32             forced; /* packets dropped for exceeding limits */
        u32             forced; /* packets dropped for exceeding limits */
        u32             early;  /* packets dropped as a warning */
        u32             early;  /* packets dropped as a warning */
        u32             other;  /* packets dropped by invoking drop() */
        u32             other;  /* packets dropped by invoking drop() */
        u32             pdrop;  /* packets dropped because we exceeded physical queue limits */
        u32             pdrop;  /* packets dropped because we exceeded physical queue limits */
        char            Scell_log;
        char            Scell_log;
        u8              Stab[256];
        u8              Stab[256];
        u8              prio;        /* the prio of this vq */
        u8              prio;        /* the prio of this vq */
 
 
/* Variables */
/* Variables */
        unsigned long   qave;           /* Average queue length: A scaled */
        unsigned long   qave;           /* Average queue length: A scaled */
        int             qcount;         /* Packets since last random number generation */
        int             qcount;         /* Packets since last random number generation */
        u32             qR;             /* Cached random number */
        u32             qR;             /* Cached random number */
 
 
        psched_time_t   qidlestart;     /* Start of idle period */
        psched_time_t   qidlestart;     /* Start of idle period */
};
};
 
 
struct gred_sched
struct gred_sched
{
{
        struct gred_sched_data *tab[MAX_DPs];
        struct gred_sched_data *tab[MAX_DPs];
        u32             DPs;
        u32             DPs;
        u32             def;
        u32             def;
        u8              initd;
        u8              initd;
        u8              grio;
        u8              grio;
        u8              eqp;
        u8              eqp;
};
};
 
 
static int
static int
gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
{
        psched_time_t now;
        psched_time_t now;
        struct gred_sched_data *q=NULL;
        struct gred_sched_data *q=NULL;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        unsigned long   qave=0;
        unsigned long   qave=0;
        int i=0;
        int i=0;
 
 
        if (!t->initd && skb_queue_len(&sch->q) < (sch->dev->tx_queue_len ? : 1)) {
        if (!t->initd && skb_queue_len(&sch->q) < (sch->dev->tx_queue_len ? : 1)) {
                D2PRINTK("NO GRED Queues setup yet! Enqueued anyway\n");
                D2PRINTK("NO GRED Queues setup yet! Enqueued anyway\n");
                goto do_enqueue;
                goto do_enqueue;
        }
        }
 
 
 
 
        if ( ((skb->tc_index&0xf) > (t->DPs -1)) || !(q=t->tab[skb->tc_index&0xf])) {
        if ( ((skb->tc_index&0xf) > (t->DPs -1)) || !(q=t->tab[skb->tc_index&0xf])) {
                printk("GRED: setting to default (%d)\n ",t->def);
                printk("GRED: setting to default (%d)\n ",t->def);
                if (!(q=t->tab[t->def])) {
                if (!(q=t->tab[t->def])) {
                        DPRINTK("GRED: setting to default FAILED! dropping!! "
                        DPRINTK("GRED: setting to default FAILED! dropping!! "
                            "(%d)\n ", t->def);
                            "(%d)\n ", t->def);
                        goto drop;
                        goto drop;
                }
                }
                /* fix tc_index? --could be controvesial but needed for
                /* fix tc_index? --could be controvesial but needed for
                   requeueing */
                   requeueing */
                skb->tc_index=(skb->tc_index&0xfffffff0) | t->def;
                skb->tc_index=(skb->tc_index&0xfffffff0) | t->def;
        }
        }
 
 
        D2PRINTK("gred_enqueue virtualQ 0x%x classid %x backlog %d "
        D2PRINTK("gred_enqueue virtualQ 0x%x classid %x backlog %d "
            "general backlog %d\n",skb->tc_index&0xf,sch->handle,q->backlog,
            "general backlog %d\n",skb->tc_index&0xf,sch->handle,q->backlog,
            sch->stats.backlog);
            sch->stats.backlog);
        /* sum up all the qaves of prios <= to ours to get the new qave*/
        /* sum up all the qaves of prios <= to ours to get the new qave*/
        if (!t->eqp && t->grio) {
        if (!t->eqp && t->grio) {
                for (i=0;i<t->DPs;i++) {
                for (i=0;i<t->DPs;i++) {
                        if ((!t->tab[i]) || (i==q->DP))
                        if ((!t->tab[i]) || (i==q->DP))
                                continue;
                                continue;
 
 
                        if ((t->tab[i]->prio < q->prio) && (PSCHED_IS_PASTPERFECT(t->tab[i]->qidlestart)))
                        if ((t->tab[i]->prio < q->prio) && (PSCHED_IS_PASTPERFECT(t->tab[i]->qidlestart)))
                                qave +=t->tab[i]->qave;
                                qave +=t->tab[i]->qave;
                }
                }
 
 
        }
        }
 
 
        q->packetsin++;
        q->packetsin++;
        q->bytesin+=skb->len;
        q->bytesin+=skb->len;
 
 
        if (t->eqp && t->grio) {
        if (t->eqp && t->grio) {
                qave=0;
                qave=0;
                q->qave=t->tab[t->def]->qave;
                q->qave=t->tab[t->def]->qave;
                q->qidlestart=t->tab[t->def]->qidlestart;
                q->qidlestart=t->tab[t->def]->qidlestart;
        }
        }
 
 
        if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) {
        if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) {
                long us_idle;
                long us_idle;
                PSCHED_GET_TIME(now);
                PSCHED_GET_TIME(now);
                us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0);
                us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0);
                PSCHED_SET_PASTPERFECT(q->qidlestart);
                PSCHED_SET_PASTPERFECT(q->qidlestart);
 
 
                q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF];
                q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF];
        } else {
        } else {
                if (t->eqp) {
                if (t->eqp) {
                        q->qave += sch->stats.backlog - (q->qave >> q->Wlog);
                        q->qave += sch->stats.backlog - (q->qave >> q->Wlog);
                } else {
                } else {
                        q->qave += q->backlog - (q->qave >> q->Wlog);
                        q->qave += q->backlog - (q->qave >> q->Wlog);
                }
                }
 
 
        }
        }
 
 
 
 
        if (t->eqp && t->grio)
        if (t->eqp && t->grio)
                t->tab[t->def]->qave=q->qave;
                t->tab[t->def]->qave=q->qave;
 
 
        if ((q->qave+qave) < q->qth_min) {
        if ((q->qave+qave) < q->qth_min) {
                q->qcount = -1;
                q->qcount = -1;
enqueue:
enqueue:
                if (q->backlog + skb->len <= q->limit) {
                if (q->backlog + skb->len <= q->limit) {
                        q->backlog += skb->len;
                        q->backlog += skb->len;
do_enqueue:
do_enqueue:
                        __skb_queue_tail(&sch->q, skb);
                        __skb_queue_tail(&sch->q, skb);
                        sch->stats.backlog += skb->len;
                        sch->stats.backlog += skb->len;
                        sch->stats.bytes += skb->len;
                        sch->stats.bytes += skb->len;
                        sch->stats.packets++;
                        sch->stats.packets++;
                        return 0;
                        return 0;
                } else {
                } else {
                        q->pdrop++;
                        q->pdrop++;
                }
                }
 
 
drop:
drop:
                kfree_skb(skb);
                kfree_skb(skb);
                sch->stats.drops++;
                sch->stats.drops++;
                return NET_XMIT_DROP;
                return NET_XMIT_DROP;
        }
        }
        if ((q->qave+qave) >= q->qth_max) {
        if ((q->qave+qave) >= q->qth_max) {
                q->qcount = -1;
                q->qcount = -1;
                sch->stats.overlimits++;
                sch->stats.overlimits++;
                q->forced++;
                q->forced++;
                goto drop;
                goto drop;
        }
        }
        if (++q->qcount) {
        if (++q->qcount) {
                if ((((qave+q->qave) - q->qth_min)>>q->Wlog)*q->qcount < q->qR)
                if ((((qave+q->qave) - q->qth_min)>>q->Wlog)*q->qcount < q->qR)
                        goto enqueue;
                        goto enqueue;
                q->qcount = 0;
                q->qcount = 0;
                q->qR = net_random()&q->Rmask;
                q->qR = net_random()&q->Rmask;
                sch->stats.overlimits++;
                sch->stats.overlimits++;
                q->early++;
                q->early++;
                goto drop;
                goto drop;
        }
        }
        q->qR = net_random()&q->Rmask;
        q->qR = net_random()&q->Rmask;
        goto enqueue;
        goto enqueue;
}
}
 
 
static int
static int
gred_requeue(struct sk_buff *skb, struct Qdisc* sch)
gred_requeue(struct sk_buff *skb, struct Qdisc* sch)
{
{
        struct gred_sched_data *q;
        struct gred_sched_data *q;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        q= t->tab[(skb->tc_index&0xf)];
        q= t->tab[(skb->tc_index&0xf)];
/* error checking here -- probably unnecessary */
/* error checking here -- probably unnecessary */
        PSCHED_SET_PASTPERFECT(q->qidlestart);
        PSCHED_SET_PASTPERFECT(q->qidlestart);
 
 
        __skb_queue_head(&sch->q, skb);
        __skb_queue_head(&sch->q, skb);
        sch->stats.backlog += skb->len;
        sch->stats.backlog += skb->len;
        q->backlog += skb->len;
        q->backlog += skb->len;
        return 0;
        return 0;
}
}
 
 
static struct sk_buff *
static struct sk_buff *
gred_dequeue(struct Qdisc* sch)
gred_dequeue(struct Qdisc* sch)
{
{
        struct sk_buff *skb;
        struct sk_buff *skb;
        struct gred_sched_data *q;
        struct gred_sched_data *q;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        struct gred_sched *t= (struct gred_sched *)sch->data;
 
 
        skb = __skb_dequeue(&sch->q);
        skb = __skb_dequeue(&sch->q);
        if (skb) {
        if (skb) {
                sch->stats.backlog -= skb->len;
                sch->stats.backlog -= skb->len;
                q= t->tab[(skb->tc_index&0xf)];
                q= t->tab[(skb->tc_index&0xf)];
                if (q) {
                if (q) {
                        q->backlog -= skb->len;
                        q->backlog -= skb->len;
                        if (!q->backlog && !t->eqp)
                        if (!q->backlog && !t->eqp)
                                PSCHED_GET_TIME(q->qidlestart);
                                PSCHED_GET_TIME(q->qidlestart);
                } else {
                } else {
                        D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf);
                        D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf);
                }
                }
                return skb;
                return skb;
        }
        }
 
 
        if (t->eqp) {
        if (t->eqp) {
                        q= t->tab[t->def];
                        q= t->tab[t->def];
                        if (!q)
                        if (!q)
                                D2PRINTK("no default VQ set: Results will be "
                                D2PRINTK("no default VQ set: Results will be "
                                       "screwed up\n");
                                       "screwed up\n");
                        else
                        else
                                PSCHED_GET_TIME(q->qidlestart);
                                PSCHED_GET_TIME(q->qidlestart);
        }
        }
 
 
        return NULL;
        return NULL;
}
}
 
 
static unsigned int gred_drop(struct Qdisc* sch)
static unsigned int gred_drop(struct Qdisc* sch)
{
{
        struct sk_buff *skb;
        struct sk_buff *skb;
 
 
        struct gred_sched_data *q;
        struct gred_sched_data *q;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        struct gred_sched *t= (struct gred_sched *)sch->data;
 
 
        skb = __skb_dequeue_tail(&sch->q);
        skb = __skb_dequeue_tail(&sch->q);
        if (skb) {
        if (skb) {
                unsigned int len = skb->len;
                unsigned int len = skb->len;
                sch->stats.backlog -= len;
                sch->stats.backlog -= len;
                sch->stats.drops++;
                sch->stats.drops++;
                q= t->tab[(skb->tc_index&0xf)];
                q= t->tab[(skb->tc_index&0xf)];
                if (q) {
                if (q) {
                        q->backlog -= len;
                        q->backlog -= len;
                        q->other++;
                        q->other++;
                        if (!q->backlog && !t->eqp)
                        if (!q->backlog && !t->eqp)
                                PSCHED_GET_TIME(q->qidlestart);
                                PSCHED_GET_TIME(q->qidlestart);
                } else {
                } else {
                        D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf);
                        D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf);
                }
                }
 
 
                kfree_skb(skb);
                kfree_skb(skb);
                return len;
                return len;
        }
        }
 
 
        q=t->tab[t->def];
        q=t->tab[t->def];
        if (!q) {
        if (!q) {
                D2PRINTK("no default VQ set: Results might be screwed up\n");
                D2PRINTK("no default VQ set: Results might be screwed up\n");
                return 0;
                return 0;
        }
        }
 
 
        PSCHED_GET_TIME(q->qidlestart);
        PSCHED_GET_TIME(q->qidlestart);
        return 0;
        return 0;
 
 
}
}
 
 
static void gred_reset(struct Qdisc* sch)
static void gred_reset(struct Qdisc* sch)
{
{
        int i;
        int i;
        struct gred_sched_data *q;
        struct gred_sched_data *q;
        struct gred_sched *t= (struct gred_sched *)sch->data;
        struct gred_sched *t= (struct gred_sched *)sch->data;
 
 
        __skb_queue_purge(&sch->q);
        __skb_queue_purge(&sch->q);
 
 
        sch->stats.backlog = 0;
        sch->stats.backlog = 0;
 
 
        for (i=0;i<t->DPs;i++) {
        for (i=0;i<t->DPs;i++) {
                q= t->tab[i];
                q= t->tab[i];
                if (!q)
                if (!q)
                        continue;
                        continue;
                PSCHED_SET_PASTPERFECT(q->qidlestart);
                PSCHED_SET_PASTPERFECT(q->qidlestart);
                q->qave = 0;
                q->qave = 0;
                q->qcount = -1;
                q->qcount = -1;
                q->backlog = 0;
                q->backlog = 0;
                q->other=0;
                q->other=0;
                q->forced=0;
                q->forced=0;
                q->pdrop=0;
                q->pdrop=0;
                q->early=0;
                q->early=0;
        }
        }
}
}
 
 
static int gred_change(struct Qdisc *sch, struct rtattr *opt)
static int gred_change(struct Qdisc *sch, struct rtattr *opt)
{
{
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct gred_sched_data *q;
        struct gred_sched_data *q;
        struct tc_gred_qopt *ctl;
        struct tc_gred_qopt *ctl;
        struct tc_gred_sopt *sopt;
        struct tc_gred_sopt *sopt;
        struct rtattr *tb[TCA_GRED_STAB];
        struct rtattr *tb[TCA_GRED_STAB];
        struct rtattr *tb2[TCA_GRED_DPS];
        struct rtattr *tb2[TCA_GRED_DPS];
        int i;
        int i;
 
 
        if (opt == NULL ||
        if (opt == NULL ||
                rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
                rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
                        return -EINVAL;
                        return -EINVAL;
 
 
        if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) {
        if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) {
                rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),
                rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),
                    RTA_PAYLOAD(opt));
                    RTA_PAYLOAD(opt));
 
 
                if (tb2[TCA_GRED_DPS-1] == 0)
                if (tb2[TCA_GRED_DPS-1] == 0)
                        return -EINVAL;
                        return -EINVAL;
 
 
                sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
                sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
                table->DPs=sopt->DPs;
                table->DPs=sopt->DPs;
                table->def=sopt->def_DP;
                table->def=sopt->def_DP;
                table->grio=sopt->grio;
                table->grio=sopt->grio;
                table->initd=0;
                table->initd=0;
                /* probably need to clear all the table DP entries as well */
                /* probably need to clear all the table DP entries as well */
                MOD_INC_USE_COUNT;
                MOD_INC_USE_COUNT;
                return 0;
                return 0;
            }
            }
 
 
 
 
        if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 ||
        if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 ||
                RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) ||
                RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) ||
                RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256)
                RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256)
                        return -EINVAL;
                        return -EINVAL;
 
 
        ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]);
        ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]);
        if (ctl->DP > MAX_DPs-1 ) {
        if (ctl->DP > MAX_DPs-1 ) {
                /* misbehaving is punished! Put in the default drop probability */
                /* misbehaving is punished! Put in the default drop probability */
                DPRINTK("\nGRED: DP %u not in  the proper range fixed. New DP "
                DPRINTK("\nGRED: DP %u not in  the proper range fixed. New DP "
                        "set to default at %d\n",ctl->DP,table->def);
                        "set to default at %d\n",ctl->DP,table->def);
                ctl->DP=table->def;
                ctl->DP=table->def;
        }
        }
 
 
        if (table->tab[ctl->DP] == NULL) {
        if (table->tab[ctl->DP] == NULL) {
                table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data),
                table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data),
                                            GFP_KERNEL);
                                            GFP_KERNEL);
                if (NULL == table->tab[ctl->DP])
                if (NULL == table->tab[ctl->DP])
                        return -ENOMEM;
                        return -ENOMEM;
                memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data)));
                memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data)));
        }
        }
        q= table->tab[ctl->DP];
        q= table->tab[ctl->DP];
 
 
        if (table->grio) {
        if (table->grio) {
                if (ctl->prio <=0) {
                if (ctl->prio <=0) {
                        if (table->def && table->tab[table->def]) {
                        if (table->def && table->tab[table->def]) {
                                DPRINTK("\nGRED: DP %u does not have a prio"
                                DPRINTK("\nGRED: DP %u does not have a prio"
                                        "setting default to %d\n",ctl->DP,
                                        "setting default to %d\n",ctl->DP,
                                        table->tab[table->def]->prio);
                                        table->tab[table->def]->prio);
                                q->prio=table->tab[table->def]->prio;
                                q->prio=table->tab[table->def]->prio;
                        } else {
                        } else {
                                DPRINTK("\nGRED: DP %u does not have a prio"
                                DPRINTK("\nGRED: DP %u does not have a prio"
                                        " setting default to 8\n",ctl->DP);
                                        " setting default to 8\n",ctl->DP);
                                q->prio=8;
                                q->prio=8;
                        }
                        }
                } else {
                } else {
                        q->prio=ctl->prio;
                        q->prio=ctl->prio;
                }
                }
        } else {
        } else {
                q->prio=8;
                q->prio=8;
        }
        }
 
 
 
 
        q->DP=ctl->DP;
        q->DP=ctl->DP;
        q->Wlog = ctl->Wlog;
        q->Wlog = ctl->Wlog;
        q->Plog = ctl->Plog;
        q->Plog = ctl->Plog;
        q->limit = ctl->limit;
        q->limit = ctl->limit;
        q->Scell_log = ctl->Scell_log;
        q->Scell_log = ctl->Scell_log;
        q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
        q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
        q->Scell_max = (255<<q->Scell_log);
        q->Scell_max = (255<<q->Scell_log);
        q->qth_min = ctl->qth_min<<ctl->Wlog;
        q->qth_min = ctl->qth_min<<ctl->Wlog;
        q->qth_max = ctl->qth_max<<ctl->Wlog;
        q->qth_max = ctl->qth_max<<ctl->Wlog;
        q->qave=0;
        q->qave=0;
        q->backlog=0;
        q->backlog=0;
        q->qcount = -1;
        q->qcount = -1;
        q->other=0;
        q->other=0;
        q->forced=0;
        q->forced=0;
        q->pdrop=0;
        q->pdrop=0;
        q->early=0;
        q->early=0;
 
 
        PSCHED_SET_PASTPERFECT(q->qidlestart);
        PSCHED_SET_PASTPERFECT(q->qidlestart);
        memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
        memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
 
 
        if ( table->initd && table->grio) {
        if ( table->initd && table->grio) {
        /* this looks ugly but its not in the fast path */
        /* this looks ugly but its not in the fast path */
                for (i=0;i<table->DPs;i++) {
                for (i=0;i<table->DPs;i++) {
                        if ((!table->tab[i]) || (i==q->DP) )
                        if ((!table->tab[i]) || (i==q->DP) )
                                continue;
                                continue;
                        if (table->tab[i]->prio == q->prio ){
                        if (table->tab[i]->prio == q->prio ){
                                /* WRED mode detected */
                                /* WRED mode detected */
                                table->eqp=1;
                                table->eqp=1;
                                break;
                                break;
                        }
                        }
                }
                }
        }
        }
 
 
        if (!table->initd) {
        if (!table->initd) {
                table->initd=1;
                table->initd=1;
                /*
                /*
                the first entry also goes into the default until
                the first entry also goes into the default until
                over-written
                over-written
                */
                */
 
 
                if (table->tab[table->def] == NULL) {
                if (table->tab[table->def] == NULL) {
                        table->tab[table->def]=
                        table->tab[table->def]=
                                kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL);
                                kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL);
                        if (NULL == table->tab[table->def])
                        if (NULL == table->tab[table->def])
                                return -ENOMEM;
                                return -ENOMEM;
 
 
                        memset(table->tab[table->def], 0,
                        memset(table->tab[table->def], 0,
                               (sizeof(struct gred_sched_data)));
                               (sizeof(struct gred_sched_data)));
                }
                }
                q= table->tab[table->def];
                q= table->tab[table->def];
                q->DP=table->def;
                q->DP=table->def;
                q->Wlog = ctl->Wlog;
                q->Wlog = ctl->Wlog;
                q->Plog = ctl->Plog;
                q->Plog = ctl->Plog;
                q->limit = ctl->limit;
                q->limit = ctl->limit;
                q->Scell_log = ctl->Scell_log;
                q->Scell_log = ctl->Scell_log;
                q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
                q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
                q->Scell_max = (255<<q->Scell_log);
                q->Scell_max = (255<<q->Scell_log);
                q->qth_min = ctl->qth_min<<ctl->Wlog;
                q->qth_min = ctl->qth_min<<ctl->Wlog;
                q->qth_max = ctl->qth_max<<ctl->Wlog;
                q->qth_max = ctl->qth_max<<ctl->Wlog;
 
 
                if (table->grio)
                if (table->grio)
                        q->prio=table->tab[ctl->DP]->prio;
                        q->prio=table->tab[ctl->DP]->prio;
                else
                else
                        q->prio=8;
                        q->prio=8;
 
 
                q->qcount = -1;
                q->qcount = -1;
                PSCHED_SET_PASTPERFECT(q->qidlestart);
                PSCHED_SET_PASTPERFECT(q->qidlestart);
                memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
                memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
        }
        }
        return 0;
        return 0;
 
 
}
}
 
 
static int gred_init(struct Qdisc *sch, struct rtattr *opt)
static int gred_init(struct Qdisc *sch, struct rtattr *opt)
{
{
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct tc_gred_sopt *sopt;
        struct tc_gred_sopt *sopt;
        struct rtattr *tb[TCA_GRED_STAB];
        struct rtattr *tb[TCA_GRED_STAB];
        struct rtattr *tb2[TCA_GRED_DPS];
        struct rtattr *tb2[TCA_GRED_DPS];
 
 
        if (opt == NULL ||
        if (opt == NULL ||
                rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
                rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
                        return -EINVAL;
                        return -EINVAL;
 
 
        if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 ) {
        if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 ) {
                rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),RTA_PAYLOAD(opt));
                rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),RTA_PAYLOAD(opt));
 
 
                if (tb2[TCA_GRED_DPS-1] == 0)
                if (tb2[TCA_GRED_DPS-1] == 0)
                        return -EINVAL;
                        return -EINVAL;
 
 
                sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
                sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
                table->DPs=sopt->DPs;
                table->DPs=sopt->DPs;
                table->def=sopt->def_DP;
                table->def=sopt->def_DP;
                table->grio=sopt->grio;
                table->grio=sopt->grio;
                table->initd=0;
                table->initd=0;
                MOD_INC_USE_COUNT;
                MOD_INC_USE_COUNT;
                return 0;
                return 0;
        }
        }
 
 
        DPRINTK("\n GRED_INIT error!\n");
        DPRINTK("\n GRED_INIT error!\n");
        return -EINVAL;
        return -EINVAL;
}
}
 
 
static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
{
{
        unsigned long qave;
        unsigned long qave;
        struct rtattr *rta;
        struct rtattr *rta;
        struct tc_gred_qopt *opt = NULL ;
        struct tc_gred_qopt *opt = NULL ;
        struct tc_gred_qopt *dst;
        struct tc_gred_qopt *dst;
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct gred_sched_data *q;
        struct gred_sched_data *q;
        int i;
        int i;
        unsigned char    *b = skb->tail;
        unsigned char    *b = skb->tail;
 
 
        rta = (struct rtattr*)b;
        rta = (struct rtattr*)b;
        RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
        RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
 
 
        opt=kmalloc(sizeof(struct tc_gred_qopt)*MAX_DPs, GFP_KERNEL);
        opt=kmalloc(sizeof(struct tc_gred_qopt)*MAX_DPs, GFP_KERNEL);
 
 
        if (opt  == NULL) {
        if (opt  == NULL) {
                DPRINTK("gred_dump:failed to malloc for %Zd\n",
                DPRINTK("gred_dump:failed to malloc for %Zd\n",
                    sizeof(struct tc_gred_qopt)*MAX_DPs);
                    sizeof(struct tc_gred_qopt)*MAX_DPs);
                goto rtattr_failure;
                goto rtattr_failure;
        }
        }
 
 
        memset(opt, 0, (sizeof(struct tc_gred_qopt))*table->DPs);
        memset(opt, 0, (sizeof(struct tc_gred_qopt))*table->DPs);
 
 
        if (!table->initd) {
        if (!table->initd) {
                DPRINTK("NO GRED Queues setup!\n");
                DPRINTK("NO GRED Queues setup!\n");
        }
        }
 
 
        for (i=0;i<MAX_DPs;i++) {
        for (i=0;i<MAX_DPs;i++) {
                dst= &opt[i];
                dst= &opt[i];
                q= table->tab[i];
                q= table->tab[i];
 
 
                if (!q) {
                if (!q) {
                        /* hack -- fix at some point with proper message
                        /* hack -- fix at some point with proper message
                           This is how we indicate to tc that there is no VQ
                           This is how we indicate to tc that there is no VQ
                           at this DP */
                           at this DP */
 
 
                        dst->DP=MAX_DPs+i;
                        dst->DP=MAX_DPs+i;
                        continue;
                        continue;
                }
                }
 
 
                dst->limit=q->limit;
                dst->limit=q->limit;
                dst->qth_min=q->qth_min>>q->Wlog;
                dst->qth_min=q->qth_min>>q->Wlog;
                dst->qth_max=q->qth_max>>q->Wlog;
                dst->qth_max=q->qth_max>>q->Wlog;
                dst->DP=q->DP;
                dst->DP=q->DP;
                dst->backlog=q->backlog;
                dst->backlog=q->backlog;
                if (q->qave) {
                if (q->qave) {
                        if (table->eqp && table->grio) {
                        if (table->eqp && table->grio) {
                                q->qidlestart=table->tab[table->def]->qidlestart;
                                q->qidlestart=table->tab[table->def]->qidlestart;
                                q->qave=table->tab[table->def]->qave;
                                q->qave=table->tab[table->def]->qave;
                        }
                        }
                        if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) {
                        if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) {
                                long idle;
                                long idle;
                                psched_time_t now;
                                psched_time_t now;
                                PSCHED_GET_TIME(now);
                                PSCHED_GET_TIME(now);
                                idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0);
                                idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0);
                                qave  = q->qave >> q->Stab[(idle>>q->Scell_log)&0xFF];
                                qave  = q->qave >> q->Stab[(idle>>q->Scell_log)&0xFF];
                                dst->qave = qave >> q->Wlog;
                                dst->qave = qave >> q->Wlog;
 
 
                        } else {
                        } else {
                                dst->qave = q->qave >> q->Wlog;
                                dst->qave = q->qave >> q->Wlog;
                        }
                        }
                } else {
                } else {
                        dst->qave = 0;
                        dst->qave = 0;
                }
                }
 
 
 
 
                dst->Wlog = q->Wlog;
                dst->Wlog = q->Wlog;
                dst->Plog = q->Plog;
                dst->Plog = q->Plog;
                dst->Scell_log = q->Scell_log;
                dst->Scell_log = q->Scell_log;
                dst->other = q->other;
                dst->other = q->other;
                dst->forced = q->forced;
                dst->forced = q->forced;
                dst->early = q->early;
                dst->early = q->early;
                dst->pdrop = q->pdrop;
                dst->pdrop = q->pdrop;
                dst->prio = q->prio;
                dst->prio = q->prio;
                dst->packets=q->packetsin;
                dst->packets=q->packetsin;
                dst->bytesin=q->bytesin;
                dst->bytesin=q->bytesin;
        }
        }
 
 
        RTA_PUT(skb, TCA_GRED_PARMS, sizeof(struct tc_gred_qopt)*MAX_DPs, opt);
        RTA_PUT(skb, TCA_GRED_PARMS, sizeof(struct tc_gred_qopt)*MAX_DPs, opt);
        rta->rta_len = skb->tail - b;
        rta->rta_len = skb->tail - b;
 
 
        kfree(opt);
        kfree(opt);
        return skb->len;
        return skb->len;
 
 
rtattr_failure:
rtattr_failure:
        if (opt)
        if (opt)
                kfree(opt);
                kfree(opt);
        DPRINTK("gred_dump: FAILURE!!!!\n");
        DPRINTK("gred_dump: FAILURE!!!!\n");
 
 
/* also free the opt struct here */
/* also free the opt struct here */
        skb_trim(skb, b - skb->data);
        skb_trim(skb, b - skb->data);
        return -1;
        return -1;
}
}
 
 
static void gred_destroy(struct Qdisc *sch)
static void gred_destroy(struct Qdisc *sch)
{
{
        struct gred_sched *table = (struct gred_sched *)sch->data;
        struct gred_sched *table = (struct gred_sched *)sch->data;
        int i;
        int i;
 
 
        for (i = 0;i < table->DPs; i++) {
        for (i = 0;i < table->DPs; i++) {
                if (table->tab[i])
                if (table->tab[i])
                        kfree(table->tab[i]);
                        kfree(table->tab[i]);
        }
        }
        MOD_DEC_USE_COUNT;
        MOD_DEC_USE_COUNT;
}
}
 
 
struct Qdisc_ops gred_qdisc_ops =
struct Qdisc_ops gred_qdisc_ops =
{
{
        NULL,
        NULL,
        NULL,
        NULL,
        "gred",
        "gred",
        sizeof(struct gred_sched),
        sizeof(struct gred_sched),
        gred_enqueue,
        gred_enqueue,
        gred_dequeue,
        gred_dequeue,
        gred_requeue,
        gred_requeue,
        gred_drop,
        gred_drop,
        gred_init,
        gred_init,
        gred_reset,
        gred_reset,
        gred_destroy,
        gred_destroy,
        gred_change, /* change */
        gred_change, /* change */
        gred_dump,
        gred_dump,
};
};
 
 
 
 
#ifdef MODULE
#ifdef MODULE
int init_module(void)
int init_module(void)
{
{
        return register_qdisc(&gred_qdisc_ops);
        return register_qdisc(&gred_qdisc_ops);
}
}
 
 
void cleanup_module(void)
void cleanup_module(void)
{
{
        unregister_qdisc(&gred_qdisc_ops);
        unregister_qdisc(&gred_qdisc_ops);
}
}
#endif
#endif
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.