aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/hack-5.4/641-sch_cake-fix-IP-protocol-handling-in-the-presence-of.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/hack-5.4/641-sch_cake-fix-IP-protocol-handling-in-the-presence-of.patch')
-rw-r--r--target/linux/generic/hack-5.4/641-sch_cake-fix-IP-protocol-handling-in-the-presence-of.patch114
1 files changed, 114 insertions, 0 deletions
diff --git a/target/linux/generic/hack-5.4/641-sch_cake-fix-IP-protocol-handling-in-the-presence-of.patch b/target/linux/generic/hack-5.4/641-sch_cake-fix-IP-protocol-handling-in-the-presence-of.patch
new file mode 100644
index 0000000000..e651743c1d
--- /dev/null
+++ b/target/linux/generic/hack-5.4/641-sch_cake-fix-IP-protocol-handling-in-the-presence-of.patch
@@ -0,0 +1,114 @@
+From a00590d570212c3c633bd463cef8ec7377cc7993 Mon Sep 17 00:00:00 2001
+From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Date: Tue, 30 Jun 2020 12:07:44 +0100
+Subject: [PATCH] sch_cake: fix IP protocol handling in the presence of VLAN
+ tags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilya Ponetayev <i.ponetaev@ndmsystems.com>
+
+CAKE was using the return value of tc_skb_protocol() and expecting it to be
+the IP protocol type. This can fail in the presence of QinQ VLAN tags,
+making CAKE unable to handle ECN marking and diffserv parsing in this case.
+Fix this by implementing our own version of tc_skb_protocol(), which will
+use skb->protocol directly, but also parse and skip over any VLAN tags and
+return the inner protocol number instead.
+
+Also fix CE marking by implementing a version of INET_ECN_set_ce() that
+uses the same parsing routine.
+
+Fixes: ea82511518f4 ("sch_cake: Add NAT awareness to packet classifier")
+Fixes: b2100cc56fca ("sch_cake: Use tc_skb_protocol() helper for getting packet protocol")
+Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc")
+Signed-off-by: Ilya Ponetayev <i.ponetaev@ndmsystems.com>
+[ squash original two patches, rewrite commit message ]
+Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+---
+ net/sched/sch_cake.c | 52 +++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 49 insertions(+), 3 deletions(-)
+
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -497,6 +497,52 @@ static bool cobalt_queue_empty(struct co
+ return down;
+ }
+
++static __be16 cake_skb_proto(const struct sk_buff *skb)
++{
++ unsigned int offset = skb_mac_offset(skb) + sizeof(struct ethhdr);
++ __be16 proto = skb->protocol;
++ struct vlan_hdr vhdr, *vh;
++
++ while (proto == htons(ETH_P_8021Q) || proto == htons(ETH_P_8021AD)) {
++ vh = skb_header_pointer(skb, offset, sizeof(vhdr), &vhdr);
++ if (!vh)
++ break;
++
++ proto = vh->h_vlan_encapsulated_proto;
++ offset += sizeof(vhdr);
++ }
++
++ return proto;
++}
++
++static int cake_set_ce(struct sk_buff *skb)
++{
++ int wlen = skb_network_offset(skb);
++
++ switch (cake_skb_proto(skb)) {
++ case htons(ETH_P_IP):
++ wlen += sizeof(struct iphdr);
++ if (!pskb_may_pull(skb, wlen) ||
++ skb_try_make_writable(skb, wlen))
++ return 0;
++
++ return IP_ECN_set_ce(ip_hdr(skb));
++
++ case htons(ETH_P_IPV6):
++ wlen += sizeof(struct ipv6hdr);
++ if (!pskb_may_pull(skb, wlen) ||
++ skb_try_make_writable(skb, wlen))
++ return 0;
++
++ return IP6_ECN_set_ce(skb, ipv6_hdr(skb));
++
++ default:
++ return 0;
++ }
++
++ return 0;
++}
++
+ /* Call this with a freshly dequeued packet for possible congestion marking.
+ * Returns true as an instruction to drop the packet, false for delivery.
+ */
+@@ -549,7 +595,7 @@ static bool cobalt_should_drop(struct co
+
+ if (next_due && vars->dropping) {
+ /* Use ECN mark if possible, otherwise drop */
+- drop = !(vars->ecn_marked = INET_ECN_set_ce(skb));
++ drop = !(vars->ecn_marked = cake_set_ce(skb));
+
+ vars->count++;
+ if (!vars->count)
+@@ -592,7 +638,7 @@ static bool cake_update_flowkeys(struct
+ bool rev = !skb->_nfct, upd = false;
+ __be32 ip;
+
+- if (tc_skb_protocol(skb) != htons(ETH_P_IP))
++ if (cake_skb_proto(skb) != htons(ETH_P_IP))
+ return false;
+
+ if (!nf_ct_get_tuple_skb(&tuple, skb))
+@@ -1557,7 +1603,7 @@ static u8 cake_handle_diffserv(struct sk
+ u16 *buf, buf_;
+ u8 dscp;
+
+- switch (tc_skb_protocol(skb)) {
++ switch (cake_skb_proto(skb)) {
+ case htons(ETH_P_IP):
+ buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_);
+ if (unlikely(!buf))