Skip to content

Commit 7126399

Browse files
gamanakisdavem330
authored andcommitted
sch_cake: Make the dual modes fairer
CAKE host fairness does not work well with TCP flows in dual-srchost and dual-dsthost setup. The reason is that ACKs generated by TCP flows are classified as sparse flows, and affect flow isolation from other hosts. Fix this by calculating host_load based only on the bulk flows a host generates. In a hash collision the host_bulk_flow_count values must be decremented on the old hosts and incremented on the new ones *if* the queue is in the bulk set. Reported-by: Pete Heist <[email protected]> Signed-off-by: George Amanakis <[email protected]> Signed-off-by: Toke Høiland-Jørgensen <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c21e18a commit 7126399

File tree

1 file changed

+63
-29
lines changed

1 file changed

+63
-29
lines changed

net/sched/sch_cake.c

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ struct cake_flow {
138138
struct cake_host {
139139
u32 srchost_tag;
140140
u32 dsthost_tag;
141-
u16 srchost_refcnt;
142-
u16 dsthost_refcnt;
141+
u16 srchost_bulk_flow_count;
142+
u16 dsthost_bulk_flow_count;
143143
};
144144

145145
struct cake_heap_entry {
@@ -746,8 +746,10 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
746746
* queue, accept the collision, update the host tags.
747747
*/
748748
q->way_collisions++;
749-
q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--;
750-
q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--;
749+
if (q->flows[outer_hash + k].set == CAKE_SET_BULK) {
750+
q->hosts[q->flows[reduced_hash].srchost].srchost_bulk_flow_count--;
751+
q->hosts[q->flows[reduced_hash].dsthost].dsthost_bulk_flow_count--;
752+
}
751753
allocate_src = cake_dsrc(flow_mode);
752754
allocate_dst = cake_ddst(flow_mode);
753755
found:
@@ -767,13 +769,14 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
767769
}
768770
for (i = 0; i < CAKE_SET_WAYS;
769771
i++, k = (k + 1) % CAKE_SET_WAYS) {
770-
if (!q->hosts[outer_hash + k].srchost_refcnt)
772+
if (!q->hosts[outer_hash + k].srchost_bulk_flow_count)
771773
break;
772774
}
773775
q->hosts[outer_hash + k].srchost_tag = srchost_hash;
774776
found_src:
775777
srchost_idx = outer_hash + k;
776-
q->hosts[srchost_idx].srchost_refcnt++;
778+
if (q->flows[reduced_hash].set == CAKE_SET_BULK)
779+
q->hosts[srchost_idx].srchost_bulk_flow_count++;
777780
q->flows[reduced_hash].srchost = srchost_idx;
778781
}
779782

@@ -789,13 +792,14 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
789792
}
790793
for (i = 0; i < CAKE_SET_WAYS;
791794
i++, k = (k + 1) % CAKE_SET_WAYS) {
792-
if (!q->hosts[outer_hash + k].dsthost_refcnt)
795+
if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count)
793796
break;
794797
}
795798
q->hosts[outer_hash + k].dsthost_tag = dsthost_hash;
796799
found_dst:
797800
dsthost_idx = outer_hash + k;
798-
q->hosts[dsthost_idx].dsthost_refcnt++;
801+
if (q->flows[reduced_hash].set == CAKE_SET_BULK)
802+
q->hosts[dsthost_idx].dsthost_bulk_flow_count++;
799803
q->flows[reduced_hash].dsthost = dsthost_idx;
800804
}
801805
}
@@ -1794,20 +1798,30 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
17941798
b->sparse_flow_count++;
17951799

17961800
if (cake_dsrc(q->flow_mode))
1797-
host_load = max(host_load, srchost->srchost_refcnt);
1801+
host_load = max(host_load, srchost->srchost_bulk_flow_count);
17981802

17991803
if (cake_ddst(q->flow_mode))
1800-
host_load = max(host_load, dsthost->dsthost_refcnt);
1804+
host_load = max(host_load, dsthost->dsthost_bulk_flow_count);
18011805

18021806
flow->deficit = (b->flow_quantum *
18031807
quantum_div[host_load]) >> 16;
18041808
} else if (flow->set == CAKE_SET_SPARSE_WAIT) {
1809+
struct cake_host *srchost = &b->hosts[flow->srchost];
1810+
struct cake_host *dsthost = &b->hosts[flow->dsthost];
1811+
18051812
/* this flow was empty, accounted as a sparse flow, but actually
18061813
* in the bulk rotation.
18071814
*/
18081815
flow->set = CAKE_SET_BULK;
18091816
b->sparse_flow_count--;
18101817
b->bulk_flow_count++;
1818+
1819+
if (cake_dsrc(q->flow_mode))
1820+
srchost->srchost_bulk_flow_count++;
1821+
1822+
if (cake_ddst(q->flow_mode))
1823+
dsthost->dsthost_bulk_flow_count++;
1824+
18111825
}
18121826

18131827
if (q->buffer_used > q->buffer_max_used)
@@ -1975,23 +1989,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
19751989
dsthost = &b->hosts[flow->dsthost];
19761990
host_load = 1;
19771991

1978-
if (cake_dsrc(q->flow_mode))
1979-
host_load = max(host_load, srchost->srchost_refcnt);
1980-
1981-
if (cake_ddst(q->flow_mode))
1982-
host_load = max(host_load, dsthost->dsthost_refcnt);
1983-
1984-
WARN_ON(host_load > CAKE_QUEUES);
1985-
19861992
/* flow isolation (DRR++) */
19871993
if (flow->deficit <= 0) {
1988-
/* The shifted prandom_u32() is a way to apply dithering to
1989-
* avoid accumulating roundoff errors
1990-
*/
1991-
flow->deficit += (b->flow_quantum * quantum_div[host_load] +
1992-
(prandom_u32() >> 16)) >> 16;
1993-
list_move_tail(&flow->flowchain, &b->old_flows);
1994-
19951994
/* Keep all flows with deficits out of the sparse and decaying
19961995
* rotations. No non-empty flow can go into the decaying
19971996
* rotation, so they can't get deficits
@@ -2000,6 +1999,13 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
20001999
if (flow->head) {
20012000
b->sparse_flow_count--;
20022001
b->bulk_flow_count++;
2002+
2003+
if (cake_dsrc(q->flow_mode))
2004+
srchost->srchost_bulk_flow_count++;
2005+
2006+
if (cake_ddst(q->flow_mode))
2007+
dsthost->dsthost_bulk_flow_count++;
2008+
20032009
flow->set = CAKE_SET_BULK;
20042010
} else {
20052011
/* we've moved it to the bulk rotation for
@@ -2009,6 +2015,22 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
20092015
flow->set = CAKE_SET_SPARSE_WAIT;
20102016
}
20112017
}
2018+
2019+
if (cake_dsrc(q->flow_mode))
2020+
host_load = max(host_load, srchost->srchost_bulk_flow_count);
2021+
2022+
if (cake_ddst(q->flow_mode))
2023+
host_load = max(host_load, dsthost->dsthost_bulk_flow_count);
2024+
2025+
WARN_ON(host_load > CAKE_QUEUES);
2026+
2027+
/* The shifted prandom_u32() is a way to apply dithering to
2028+
* avoid accumulating roundoff errors
2029+
*/
2030+
flow->deficit += (b->flow_quantum * quantum_div[host_load] +
2031+
(prandom_u32() >> 16)) >> 16;
2032+
list_move_tail(&flow->flowchain, &b->old_flows);
2033+
20122034
goto retry;
20132035
}
20142036

@@ -2029,6 +2051,13 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
20292051
&b->decaying_flows);
20302052
if (flow->set == CAKE_SET_BULK) {
20312053
b->bulk_flow_count--;
2054+
2055+
if (cake_dsrc(q->flow_mode))
2056+
srchost->srchost_bulk_flow_count--;
2057+
2058+
if (cake_ddst(q->flow_mode))
2059+
dsthost->dsthost_bulk_flow_count--;
2060+
20322061
b->decaying_flow_count++;
20332062
} else if (flow->set == CAKE_SET_SPARSE ||
20342063
flow->set == CAKE_SET_SPARSE_WAIT) {
@@ -2042,14 +2071,19 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
20422071
if (flow->set == CAKE_SET_SPARSE ||
20432072
flow->set == CAKE_SET_SPARSE_WAIT)
20442073
b->sparse_flow_count--;
2045-
else if (flow->set == CAKE_SET_BULK)
2074+
else if (flow->set == CAKE_SET_BULK) {
20462075
b->bulk_flow_count--;
2047-
else
2076+
2077+
if (cake_dsrc(q->flow_mode))
2078+
srchost->srchost_bulk_flow_count--;
2079+
2080+
if (cake_ddst(q->flow_mode))
2081+
dsthost->dsthost_bulk_flow_count--;
2082+
2083+
} else
20482084
b->decaying_flow_count--;
20492085

20502086
flow->set = CAKE_SET_NONE;
2051-
srchost->srchost_refcnt--;
2052-
dsthost->dsthost_refcnt--;
20532087
}
20542088
goto begin;
20552089
}

0 commit comments

Comments
 (0)