/* CHOKe stateless AQM for fair bandwidth allocation =================================================
CHOKe (CHOose and Keep for responsive flows, CHOose and Kill for unresponsive flows) is a variant of RED that penalizes misbehaving flows but maintains no flow state. The difference from RED is an additional step during the enqueuing process. If average queue size is over the low threshold (qmin), a packet is chosen at random from the queue. If both the new and chosen packet are from the same flow, both are dropped. Unlike RED, CHOKe is not really a "classful" qdisc because it needs to access packets in queue randomly. It has a minimal class interface to allow overriding the builtin flow classifier with filters.
Source: R. Pan, B. Prabhakar, and K. Psounis, "CHOKe, A Stateless Active Queue Management Scheme for Approximating Fair Bandwidth Allocation", IEEE INFOCOM, 2000.
A. Tang, J. Wang, S. Low, "Understanding CHOKe: Throughput and Spatial Characteristics", IEEE/ACM Transactions on Networking, 2004
*/
/* Upper bound on size of sk_buff table (packets) */ #define CHOKE_MAX_QUEUE (128*1024 - 1)
/* Variables */ struct red_vars vars; struct {
u32 prob_drop; /* Early probability drops */
u32 prob_mark; /* Early probability marks */
u32 forced_drop; /* Forced drops, qavg > max_thresh */
u32 forced_mark; /* Forced marks, qavg > max_thresh */
u32 pdrop; /* Drops due to queue limits */
u32 matched; /* Drops to flow match */
} stats;
unsignedint head; unsignedint tail;
unsignedint tab_mask; /* size - 1 */
struct sk_buff **tab;
};
/* number of elements in queue including holes */ staticunsignedint choke_len(conststruct choke_sched_data *q)
{ return (q->tail - q->head) & q->tab_mask;
}
/* Should packets over max just be dropped (versus marked) */ staticint use_harddrop(conststruct choke_sched_data *q)
{ return q->flags & TC_RED_HARDDROP;
}
/* Move head pointer forward to skip over holes */ staticvoid choke_zap_head_holes(struct choke_sched_data *q)
{ do {
q->head = (q->head + 1) & q->tab_mask; if (q->head == q->tail) break;
} while (q->tab[q->head] == NULL);
}
/* Move tail pointer backwards to reuse holes */ staticvoid choke_zap_tail_holes(struct choke_sched_data *q)
{ do {
q->tail = (q->tail - 1) & q->tab_mask; if (q->head == q->tail) break;
} while (q->tab[q->tail] == NULL);
}
/* Drop packet from queue array by creating a "hole" */ staticvoid choke_drop_by_idx(struct Qdisc *sch, unsignedint idx, struct sk_buff **to_free)
{ struct choke_sched_data *q = qdisc_priv(sch); struct sk_buff *skb = q->tab[idx];
q->tab[idx] = NULL;
if (idx == q->head)
choke_zap_head_holes(q); if (idx == q->tail)
choke_zap_tail_holes(q);
/* * Compare flow of two packets * Returns true only if source and destination address and port match. * false for special cases
*/ staticbool choke_match_flow(struct sk_buff *skb1, struct sk_buff *skb2)
{ struct flow_keys temp;
if (skb1->protocol != skb2->protocol) returnfalse;
/* * Select a packet at random from queue * HACK: since queue can have holes from previous deletion; retry several * times to find a random skb but then just give up and return the head * Will return NULL if queue is empty (q->head == q->tail)
*/ staticstruct sk_buff *choke_peek_random(conststruct choke_sched_data *q, unsignedint *pidx)
{ struct sk_buff *skb; int retrys = 3;
do {
*pidx = (q->head + get_random_u32_below(choke_len(q))) & q->tab_mask;
skb = q->tab[*pidx]; if (skb) return skb;
} while (--retrys > 0);
return q->tab[*pidx = q->head];
}
/* * Compare new packet with random packet in queue * returns true if matched and sets *pidx
*/ staticbool choke_match_random(conststruct choke_sched_data *q, struct sk_buff *nskb, unsignedint *pidx)
{ struct sk_buff *oskb;
choke_skb_cb(skb)->keys_valid = 0; /* Compute average queue usage (see RED) */
q->vars.qavg = red_calc_qavg(p, &q->vars, sch->q.qlen); if (red_is_idling(&q->vars))
red_end_of_idle_period(&q->vars);
/* Is queue small? */ if (q->vars.qavg <= p->qth_min)
q->vars.qcount = -1; else { unsignedint idx;
/* Draw a packet at random from queue and compare flow */ if (choke_match_random(q, skb, &idx)) {
q->stats.matched++;
choke_drop_by_idx(sch, idx, to_free); goto congestion_drop;
}
/* Queue is large, always mark/drop */ if (q->vars.qavg > p->qth_max) {
q->vars.qcount = -1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.