Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 4 Aug 2000 17:31:44 -0400 (EDT)
From:      Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
To:        bmah@cisco.com
Cc:        freebsd-net@FreeBSD.ORG
Subject:   Re: cvs commit: src/sys/netinet tcp_output.c 
Message-ID:  <200008042131.RAA33779@khavrinen.lcs.mit.edu>
In-Reply-To: <200008042107.e74L7Tu13995@bmah-freebsd-0.cisco.com>
References:  <200008042014.QAA05452@cholla.INRS-Telecom.UQuebec.CA> <200008042107.e74L7Tu13995@bmah-freebsd-0.cisco.com>

next in thread | previous in thread | raw e-mail | index | archive | help
<<On Fri, 04 Aug 2000 14:07:29 -0700, bmah@cisco.com (Bruce A. Mah) said:

> A RED queue would drop a random packet from the full queue.

Actually, no.  A RED queue would drop a packet as it is enqueued, at
random intervals which depend on the current length of the queue.
Many people get this wrong when the idea is first explained to them; I
know I did.  Read the paper for a full explanation of how this works.[1]

> If you can get those flows to back off (e.g. TCP congestion
> control),

Specifically, I think the problem with Archie's patch is that it might
result in TCP not backing off at all.  RED doesn't deal well with
unresponsive flows.

-GAWollman

[1] In essence, when the average length x [2] exceeds threshold
th_min, start dropping packets at probability proportional to (x -
th_min).  When x exceeds threshold th_max, drop all packets.  There
are good mathematical tricks to make this very efficient for packets
which are not dropped.[3]

[2] As computed using a low-pass filter (exponential weighted moving
average).

[3] Here is some code I wrote a long time ago, written along the lines
suggested in the paper.  Some of it is probably wrong, since I never
finished testing it:

static inline int
if_enq_drop(struct ifqueue *ifq, struct mbuf *m)
{
        int marked;
        u_int newlen, new_avglen;

        if (ifq->ifq_instlen) {
                newlen = ifq->ifq_instlen + 1;
                new_avglen = ifq->ifq_avg +
                        ((newlen << (RED_AVG_SCALE - RED_W_Q_SHIFT))
                         - (ifq->ifq_avg >> RED_W_Q_SHIFT));
        } else {
                newlen = 1;
                new_avglen = if_red_unidle(ifq);
        }

        if (new_avglen < RED_MIN_TH_SCALED) {
                ifq->ifq_red_count = -1;
                marked = 0;
        } else {
                marked = if_red_domark(new_avglen, ifq);
        }
        if (marked) {
                ifq->ifq_drops++;
/* XXX DEBUG */
                printf("%p: marked a packet, instlen %u, avglen %u\n",
                       (void *)ifq,
                       ifq->ifq_instlen, ifq->ifq_avg);
/* XXX END DEBUG */
                return 0;
        }
        m->m_nextpkt = 0;
        if (ifq->ifq_tail == 0)
                ifq->ifq_head = m;
        else
                ifq->ifq_tail->m_nextpkt = m;
        ifq->ifq_tail = m;
        ifq->ifq_instlen = newlen;
        if (newlen > ifq->ifq_max_instlen)
                ifq->ifq_max_instlen = newlen;
        ifq->ifq_avg = new_avglen;
        return 1;
}

/*
 * We are called knowing that avglen is already over the threshold.
 * NB: the calculations involving R_OVER_PB are a bit suspect.  XXX
 * should test.
 */
int
if_red_domark(avglen, ifq)
        u_int avglen;
        struct ifqueue *ifq;
{
        u_int mark_prob;
        int mark_shift;
        int marked = 0;

        if (avglen < RED_MAX_TH_SCALED) {
                ifq->ifq_red_count++;
                mark_prob = (ifq->ifq_avg >> RED_PROB_C_1_SHIFT)
                                - RED_PROB_C_2_SCALED;
                /*
                 * We want to quickly approximate R/p_b, where
                 * R is a fixed-point between 0 and 1 with scale shift
                 * RED_RANDOM_SCALE, and p_b is a fixed-point between
                 * 0 and 1 with scale shift RED_AVG_SCALE.
                 * fls() gives us the highest-order bit set (numbered
                 * 1(LSB) to 32(MSB)) or zero if no bits are set.  This
                 * -log2(p_b), but for the scale factor.  We avoid using
                 * a zero value directly to make things less complicated.
                 */
                if (mark_prob == 0) mark_prob = 1; /* smallest representable */
                mark_shift = fls(mark_prob) - 1;
                /*
                 * Now, mark_shift is in the range [0..RED_AVG_SCALE];
                 * log2(p_b) would be in the range [-RED_AVG_SCALE..0],
                 * which is to say, it is mark_shift - RED_AVG_SCALE.
                 * Still with me?  C shifts only work in one direction,
                 * so what we really need is -log2(p_b), which is thus
                 * RED_AVG_SCALE - mark_shift.  But, at the same time,
                 * we also need to unscale R, so we subtract RED_RANDOM_SCALE
                 * from that shift factor (to avoid overflow).  That can
                 * sometimes turn the sign negative, so we have to be able
                 * to do two-way shifts anyway.
                 */
                mark_shift = RED_AVG_SCALE - mark_shift - RED_RANDOM_SCALE;

#define R_OVER_PB(R)    (int)(mark_shift > 0 ? \
                              (R) << mark_shift : (R) >> -mark_shift)
                if (ifq->ifq_red_count > 0 
                    && ifq->ifq_red_count >= R_OVER_PB(ifq->ifq_random)) {
                        marked = 1;
                        ifq->ifq_red_count = 0;
                }
                if (ifq->ifq_red_count == 0)
                        ifq->ifq_random = random() & RED_RANDOM_MASK;
        } else {
                marked = 1;
                ifq->ifq_red_count = -1;
        }

        return marked;
}



--
Garrett A. Wollman   | O Siem / We are all family / O Siem / We're all the same
wollman@lcs.mit.edu  | O Siem / The fires of freedom 
Opinions not those of| Dance in the burning flame
MIT, LCS, CRS, or NSA|                     - Susan Aglukark and Chad Irschick


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200008042131.RAA33779>