Skip to content

Commit

Permalink
Add support for gso splitting a la cake
Browse files Browse the repository at this point in the history
SCE markings are fine grained. I mean - *really* fine grained.
At low rates (e.g. sub 20mbit) nearly any level of GRO will
end up giving a partially SCE marked result - marking the first
packet in a GRO burst only.

As GRO ALSO messes up fq_codel in the field a lot, so being able
to split a win for a (hopefully otherwise faster fq_codel) the
mechanism I settled on here is that we:

sce_threshold: 0 - don't split don't use sce
sce_threshold: something reasonable (no idea - 2ms? 1ms? 264us?)
sce_threshold: a lot - split but don't use sce

This, along with fq_codel itself, gives me means to benchmark
the cpu costs and other changes to the algorithm fairly simply
with just the main fq_codel and fq_codel_fast codebases in place.

Compile tested only at this point.
  • Loading branch information
dtaht committed Jul 29, 2019
1 parent f00ad01 commit 9e6ab76
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
8 changes: 4 additions & 4 deletions codel_qdisc.h
Expand Up @@ -66,9 +66,9 @@ static codel_time_t codel_get_enqueue_time(const struct sk_buff *skb)
return get_codel_cb(skb)->enqueue_time;
}

static void codel_set_enqueue_time(struct sk_buff *skb)
{
get_codel_cb(skb)->enqueue_time = codel_get_time();
}
//static void codel_set_enqueue_time(struct sk_buff *skb)
//{
// get_codel_cb(skb)->enqueue_time = codel_get_time();
//}

#endif
58 changes: 50 additions & 8 deletions sch_fq_codel_fast.c
Expand Up @@ -163,13 +163,55 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch,
int uninitialized_var(ret);
unsigned int pkt_len;
bool memory_limited;
int len = qdisc_pkt_len(skb);
codel_time_t now = ktime_get_ns() >> CODEL_SHIFT;

idx = fq_codel_classify(skb, sch, &ret);
codel_set_enqueue_time(skb);

flow = &q->flows[idx];
flow_queue_add(flow, skb);
flow->backlog += qdisc_pkt_len(skb);
qdisc_qstats_backlog_inc(sch, skb);

if (skb_is_gso(skb) && q->cparams.sce_threshold) {
struct sk_buff *segs, *nskb;
netdev_features_t features = netif_skb_features(skb);
unsigned int slen = 0, numsegs = 0;

segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
if (IS_ERR_OR_NULL(segs))
return qdisc_drop(skb, sch, to_free);
while (segs) {
nskb = segs->next;
segs->next = NULL;
qdisc_skb_cb(segs)->pkt_len = segs->len; // ?
get_codel_cb(segs)->enqueue_time = now;
get_codel_cb(segs)->mem_usage = skb->truesize;
q->memory_usage += skb->truesize;

flow_queue_add(flow, segs);

sch->q.qlen++;
numsegs++;
slen += segs->len;
segs = nskb;
}

/* stats */
flow->backlog += slen;
sch->qstats.backlog += slen;
qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen);
consume_skb(skb);
} else {
/* not splitting */
get_codel_cb(skb)->enqueue_time = now;
get_codel_cb(skb)->mem_usage = skb->truesize;
q->memory_usage += skb->truesize;
flow_queue_add(flow, skb);
sch->q.qlen++;
/* stats */
flow->backlog += len;
sch->qstats.backlog += len;
}

//? qdisc_qstats_backlog_inc(sch, skb);

if(flow->backlog > q->fat_backlog) {
q->fat_flow = flow;
Expand All @@ -180,17 +222,17 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch,
list_add_tail(&flow->flowchain, &q->new_flows);
flow->deficit = q->quantum;
}
get_codel_cb(skb)->mem_usage = skb->truesize;
q->memory_usage += get_codel_cb(skb)->mem_usage;

memory_limited = q->memory_usage > q->memory_limit;
if (++sch->q.qlen <= sch->limit && !memory_limited)
if (sch->q.qlen <= sch->limit && !memory_limited)
return NET_XMIT_SUCCESS;

prev_backlog = sch->qstats.backlog;
prev_qlen = sch->q.qlen;

/* save this packet length as it might be dropped by fq_codel_drop() */
pkt_len = qdisc_pkt_len(skb);
pkt_len = qdisc_pkt_len(skb); // FIXME this is not enough - can add 42

/* fq_codel_drop() is expensive, as
* instead of dropping a single packet, it drops half of its backlog
* with a 64 packets limit to not add a too big cpu spike here.
Expand Down

0 comments on commit 9e6ab76

Please sign in to comment.