aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-4.4/035-fq_codel-fix-NET_XMIT_CN-behavior.patch
blob: a1902fea07be89f94edcba4963b1bafec129ff92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
From: Eric Dumazet <edumazet@google.com>
Date: Sat, 4 Jun 2016 12:55:13 -0700
Subject: [PATCH] fq_codel: fix NET_XMIT_CN behavior

My prior attempt to fix the backlogs of parents failed.

If we return NET_XMIT_CN, our parents wont increase their backlog,
so our qdisc_tree_reduce_backlog() should take this into account.

v2: Florian Westphal pointed out that we could drop the packet,
so we need to save qdisc_pkt_len(skb) in a temp variable before
calling fq_codel_drop()

Fixes: 9d18562a2278 ("fq_codel: add batch ability to fq_codel_drop()")
Fixes: 2ccccf5fb43f ("net_sched: update hierarchical backlog too")
Reported-by: Stas Nichiporovich <stasn77@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: WANG Cong <xiyou.wangcong@gmail.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
---

--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -197,6 +197,7 @@ static int fq_codel_enqueue(struct sk_bu
 	unsigned int idx, prev_backlog, prev_qlen;
 	struct fq_codel_flow *flow;
 	int uninitialized_var(ret);
+	unsigned int pkt_len;
 	bool memory_limited;
 
 	idx = fq_codel_classify(skb, sch, &ret);
@@ -228,6 +229,8 @@ static int fq_codel_enqueue(struct sk_bu
 	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);
 	/* fq_codel_drop() is quite expensive, as it performs a linear search
 	 * in q->backlogs[] to find a fat flow.
 	 * So instead of dropping a single packet, drop half of its backlog
@@ -235,14 +238,23 @@ static int fq_codel_enqueue(struct sk_bu
 	 */
 	ret = fq_codel_drop(sch, q->drop_batch_size);
 
-	q->drop_overlimit += prev_qlen - sch->q.qlen;
+	prev_qlen -= sch->q.qlen;
+	prev_backlog -= sch->qstats.backlog;
+	q->drop_overlimit += prev_qlen;
 	if (memory_limited)
-		q->drop_overmemory += prev_qlen - sch->q.qlen;
-	/* As we dropped packet(s), better let upper stack know this */
-	qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
-				  prev_backlog - sch->qstats.backlog);
+		q->drop_overmemory += prev_qlen;
 
-	return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS;
+	/* As we dropped packet(s), better let upper stack know this.
+	 * If we dropped a packet for this flow, return NET_XMIT_CN,
+	 * but in this case, our parents wont increase their backlogs.
+	 */
+	if (ret == idx) {
+		qdisc_tree_reduce_backlog(sch, prev_qlen - 1,
+					  prev_backlog - pkt_len);
+		return NET_XMIT_CN;
+	}
+	qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog);
+	return NET_XMIT_SUCCESS;
 }
 
 /* This is the specific function called from codel_dequeue()
/* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/ping6.c b/ping6.c
index c5ff881..ef2243f 100644
--- a/ping6.c
+++ b/ping6.c
@@ -71,9 +71,11 @@ char copyright[] =
 #include <linux/filter.h>
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
+#ifndef __UCLIBC__
 #include <resolv.h>
 
 #include "ping6_niquery.h"
+#endif /* __UCLIBC__ */
 
 #ifndef SOL_IPV6
 #define SOL_IPV6 IPPROTO_IPV6
@@ -154,6 +156,7 @@ int pmtudisc=-1;
 
 static int icmp_sock;
 
+#ifndef __UCLIBC__
 #include <openssl/md5.h>
 
 /* Node Information query */
@@ -165,6 +168,7 @@ int ni_subject_type = 0;
 char *ni_group;
 
 __u8 ni_nonce[8];
+#endif /* __UCLIBC__ */
 
 static struct in6_addr in6_anyaddr;
 static __inline__ int ipv6_addr_any(struct in6_addr *addr)
@@ -223,6 +227,7 @@ unsigned int if_name2index(const char *ifname)
 	return i;
 }
 
+#ifndef __UCLIBC__
 struct niquery_option {
 	char *name;
 	int namelen;
@@ -512,6 +517,7 @@ char *ni_groupaddr(const char *name)
 		strcat(nigroup_buf, q);
 	return nigroup_buf;
 }
+#endif /* __UCLIBC__ */
 
 int main(int argc, char *argv[])
 {
@@ -595,12 +601,14 @@ int main(int argc, char *argv[])
 		case 'V':
 			printf("ping6 utility, iputils-ss%s\n", SNAPSHOT);
 			exit(0);
+#ifndef __UCLIBC__
 		case 'N':
 			if (niquery_option_handler(optarg) < 0) {
 				usage();
 				break;
 			}
 			break;
+#endif /* __UCLIBC__ */
 		COMMON_OPTIONS
 			common_options(ch);
 			break;
@@ -663,6 +671,7 @@ int main(int argc, char *argv[])
 		argc--;
 	}
 
+#ifndef __UCLIBC__
 	if (ni_query >= 0) {
 		int i;
 		for (i = 0; i < 8; i++)
@@ -674,15 +683,20 @@ int main(int argc, char *argv[])
 			ni_subject_type = NI_SUBJ_IPV6;
 		}
 	}
+#endif /* __UCLIBC__ */
 
 	if (argc > 1)
 		usage();
 	else if (argc == 1) {
 		target = *argv;
 	} else {
+#ifndef __UCLIBC__
 		if (ni_query < 0 && ni_subject_type != NI_SUBJ_NAME)
+#endif /* __UCLIBC__ */
 			usage();
+#ifndef __UCLIBC__
 		target = ni_group;
+#endif /* __UCLIBC__ */
 	}
 
 	memset(&hints, 0, sizeof(hints));
@@ -817,7 +831,11 @@ int main(int argc, char *argv[])
 		exit(2);
 	}
 
+#ifndef __UCLIBC__
 	if (datalen >= sizeof(struct timeval) && (ni_query < 0)) {
+#else
+	if (datalen >= sizeof(struct timeval)) {
+#endif /* __UCLIBC__ */
 		/* can we time transfer */
 		timing = 1;
 	}
@@ -866,9 +884,11 @@ int main(int argc, char *argv[])
 		ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
 	}
 
+#ifndef __UCLIBC__
 	if (ni_query >= 0)
 		ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter);
 	else
+#endif /* __UCLIBC__ */
 		ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
 
 	err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
@@ -1100,6 +1120,7 @@ int build_echo(__u8 *_icmph)
 	return cc;
 }
 
+#ifndef __UCLIBC__
 int build_niquery(__u8 *_nih)
 {
 	struct ni_hdr *nih;
@@ -1125,6 +1146,7 @@ int build_niquery(__u8 *_nih)
 
 	return cc;
 }
+#endif /* __UCLIBC__ */
 
 int send_probe(void)
 {
@@ -1132,9 +1154,11 @@ int send_probe(void)
 
 	CLR((ntransmitted+1) % mx_dup_ck);
 
+#ifndef __UCLIBC__
 	if (ni_query >= 0)
 		len = build_niquery(outpack);
 	else
+#endif /* __UCLIBC__ */
 		len = build_echo(outpack);
 
 	if (cmsglen == 0) {
@@ -1176,6 +1200,7 @@ static void putchar_safe(char c)
 		printf("\\%03o", c);
 }
 
+#ifndef __UCLIBC__
 void pr_niquery_reply_name(struct ni_hdr *nih, int len)
 {
 	__u8 *h = (__u8 *)(nih + 1);
@@ -1304,6 +1329,7 @@ void pr_niquery_reply(__u8 *_nih, int len)
 	}
 	putchar(';');
 }
+#endif /* __UCLIBC__ */
 
 /*
  * parse_reply --
@@ -1353,6 +1379,7 @@ parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
 				      hops, 0, tv, pr_addr(&from->sin6_addr),
 				      pr_echo_reply))
 			return 0;
+#ifndef __UCLIBC__
 	} else if (icmph->icmp6_type == ICMPV6_NI_REPLY) {
 		struct ni_hdr *nih = (struct ni_hdr *)icmph;
 		__u16 seq = ntohs(*(__u16 *)nih->ni_nonce);
@@ -1363,6 +1390,7 @@ parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
 				      hops, 0, tv, pr_addr(&from->sin6_addr),
 				      pr_niquery_reply))
 			return 0;
+#endif /* __UCLIBC__ */
 	} else {
 		int nexthdr;
 		struct ip6_hdr *iph1 = (struct ip6_hdr*)(icmph+1);
@@ -1557,7 +1585,9 @@ void usage(void)
 "Usage: ping6 [-LUdfnqrvVaAD] [-c count] [-i interval] [-w deadline]\n"
 "             [-p pattern] [-s packetsize] [-t ttl] [-I interface]\n"
 "             [-M pmtudisc-hint] [-S sndbuf] [-F flowlabel] [-Q tclass]\n"
+#ifndef __UCLIBC__
 "             [[-N nodeinfo-option] ...]\n"
+#endif /* __UCLIBC__ */
 "             [hop1 ...] destination\n");
 	exit(2);
 }
diff --git a/ping6_niquery.h b/ping6_niquery.h
index 61a5cfa..34c31f8 100644
--- a/ping6_niquery.h
+++ b/ping6_niquery.h
@@ -1,3 +1,4 @@
+#ifndef __UCLIBC__
 #include <asm/byteorder.h>
 
 /* Node Information Query */
@@ -45,3 +46,4 @@ struct ni_hdr {
 #define NI_IPV4ADDR_F_TRUNCATE		NI_IPV6ADDR_F_TRUNCATE
 #define NI_IPV4ADDR_F_ALL		NI_IPV6ADDR_F_ALL
 
+#endif /* __UCLIBC__ */