Merge branch 'sched-A-couple-of-fixes-for-sch_cake'

Toke Høiland-Jørgensen says:

====================
sched: A couple of fixes for sch_cake

This series contains a couple of fixes for diffserv handling in sch_cake that
provide a nice speedup (with a somewhat pedantic nit fix tacked on to the end).

Not quite sure about whether this should go to stable; it does provide a nice
speedup, but it's not strictly a fix in the "correctness" sense. I lean towards
including this in stable as well, since our most important consumer of that
(OpenWrt) is likely to backport the series anyway.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-06-25 16:24:05 -07:00
commit 6aeaf26222

View File

@ -1551,32 +1551,51 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
return idx + (tin << 16);
}
static u8 cake_handle_diffserv(struct sk_buff *skb, u16 wash)
static u8 cake_handle_diffserv(struct sk_buff *skb, bool wash)
{
int wlen = skb_network_offset(skb);
const int offset = skb_network_offset(skb);
u16 *buf, buf_;
u8 dscp;
switch (tc_skb_protocol(skb)) {
case htons(ETH_P_IP):
wlen += sizeof(struct iphdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);
if (unlikely(!buf))
return 0;
dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
if (wash && dscp)
/* ToS is in the second byte of iphdr */
dscp = ipv4_get_dsfield((struct iphdr *)buf) >> 2;
if (wash && dscp) {
const int wlen = offset + sizeof(struct iphdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
return 0;
ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, 0);
}
return dscp;
case htons(ETH_P_IPV6):
wlen += sizeof(struct ipv6hdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);
if (unlikely(!buf))
return 0;
dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
if (wash && dscp)
/* Traffic class is in the first and second bytes of ipv6hdr */
dscp = ipv6_get_dsfield((struct ipv6hdr *)buf) >> 2;
if (wash && dscp) {
const int wlen = offset + sizeof(struct ipv6hdr);
if (!pskb_may_pull(skb, wlen) ||
skb_try_make_writable(skb, wlen))
return 0;
ipv6_change_dsfield(ipv6_hdr(skb), INET_ECN_MASK, 0);
}
return dscp;
case htons(ETH_P_ARP):
@ -1593,14 +1612,17 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
{
struct cake_sched_data *q = qdisc_priv(sch);
u32 tin, mark;
bool wash;
u8 dscp;
/* Tin selection: Default to diffserv-based selection, allow overriding
* using firewall marks or skb->priority.
* using firewall marks or skb->priority. Call DSCP parsing early if
* wash is enabled, otherwise defer to below to skip unneeded parsing.
*/
dscp = cake_handle_diffserv(skb,
q->rate_flags & CAKE_FLAG_WASH);
mark = (skb->mark & q->fwmark_mask) >> q->fwmark_shft;
wash = !!(q->rate_flags & CAKE_FLAG_WASH);
if (wash)
dscp = cake_handle_diffserv(skb, wash);
if (q->tin_mode == CAKE_DIFFSERV_BESTEFFORT)
tin = 0;
@ -1614,6 +1636,8 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
tin = q->tin_order[TC_H_MIN(skb->priority) - 1];
else {
if (!wash)
dscp = cake_handle_diffserv(skb, wash);
tin = q->tin_index[dscp];
if (unlikely(tin >= q->tin_cnt))
@ -2691,7 +2715,7 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
qdisc_watchdog_init(&q->watchdog, sch);
if (opt) {
int err = cake_change(sch, opt, extack);
err = cake_change(sch, opt, extack);
if (err)
return err;
@ -3008,7 +3032,7 @@ static int cake_dump_class_stats(struct Qdisc *sch, unsigned long cl,
PUT_STAT_S32(BLUE_TIMER_US,
ktime_to_us(
ktime_sub(now,
flow->cvars.blue_timer)));
flow->cvars.blue_timer)));
}
if (flow->cvars.dropping) {
PUT_STAT_S32(DROP_NEXT_US,