Commit 6aeaf262 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 1ae71d99 3f608f0c
...@@ -1551,32 +1551,51 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) ...@@ -1551,32 +1551,51 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
return idx + (tin << 16); 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; u8 dscp;
switch (tc_skb_protocol(skb)) { switch (tc_skb_protocol(skb)) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
wlen += sizeof(struct iphdr); buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);
if (!pskb_may_pull(skb, wlen) || if (unlikely(!buf))
skb_try_make_writable(skb, wlen))
return 0; return 0;
dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2; /* ToS is in the second byte of iphdr */
if (wash && dscp) 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); ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, 0);
}
return dscp; return dscp;
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
wlen += sizeof(struct ipv6hdr); buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);
if (!pskb_may_pull(skb, wlen) || if (unlikely(!buf))
skb_try_make_writable(skb, wlen))
return 0; return 0;
dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2; /* Traffic class is in the first and second bytes of ipv6hdr */
if (wash && dscp) 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); ipv6_change_dsfield(ipv6_hdr(skb), INET_ECN_MASK, 0);
}
return dscp; return dscp;
case htons(ETH_P_ARP): case htons(ETH_P_ARP):
...@@ -1593,14 +1612,17 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch, ...@@ -1593,14 +1612,17 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
{ {
struct cake_sched_data *q = qdisc_priv(sch); struct cake_sched_data *q = qdisc_priv(sch);
u32 tin, mark; u32 tin, mark;
bool wash;
u8 dscp; u8 dscp;
/* Tin selection: Default to diffserv-based selection, allow overriding /* 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; 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) if (q->tin_mode == CAKE_DIFFSERV_BESTEFFORT)
tin = 0; tin = 0;
...@@ -1614,6 +1636,8 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch, ...@@ -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]; tin = q->tin_order[TC_H_MIN(skb->priority) - 1];
else { else {
if (!wash)
dscp = cake_handle_diffserv(skb, wash);
tin = q->tin_index[dscp]; tin = q->tin_index[dscp];
if (unlikely(tin >= q->tin_cnt)) if (unlikely(tin >= q->tin_cnt))
...@@ -2691,7 +2715,7 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt, ...@@ -2691,7 +2715,7 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
qdisc_watchdog_init(&q->watchdog, sch); qdisc_watchdog_init(&q->watchdog, sch);
if (opt) { if (opt) {
int err = cake_change(sch, opt, extack); err = cake_change(sch, opt, extack);
if (err) if (err)
return err; return err;
...@@ -3008,7 +3032,7 @@ static int cake_dump_class_stats(struct Qdisc *sch, unsigned long cl, ...@@ -3008,7 +3032,7 @@ static int cake_dump_class_stats(struct Qdisc *sch, unsigned long cl,
PUT_STAT_S32(BLUE_TIMER_US, PUT_STAT_S32(BLUE_TIMER_US,
ktime_to_us( ktime_to_us(
ktime_sub(now, ktime_sub(now,
flow->cvars.blue_timer))); flow->cvars.blue_timer)));
} }
if (flow->cvars.dropping) { if (flow->cvars.dropping) {
PUT_STAT_S32(DROP_NEXT_US, PUT_STAT_S32(DROP_NEXT_US,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment