From fad8bdfa40df8636a52d770bbab010086c1976ec Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 12 May 2016 21:04:50 +0200 Subject: [PATCH] kernel: backport patches improving fq_codel drop behavior Signed-off-by: Felix Fietkau --- ...sched-introduce-qdisc_replace-helper.patch | 237 +++++++ ...ched-update-hierarchical-backlog-too.patch | 647 ++++++++++++++++++ ...l-add-batch-ability-to-fq_codel_drop.patch | 189 +++++ ...t-command-line-parameters-from-users.patch | 10 +- .../patches-4.4/531-debloat_lzma.patch | 33 +- .../645-bridge_multicast_to_unicast.patch | 5 +- .../patches-4.4/660-fq_codel_defaults.patch | 4 +- .../661-fq_codel_keep_dropped_stats.patch | 2 +- .../662-use_fq_codel_by_default.patch | 6 +- 9 files changed, 1101 insertions(+), 32 deletions(-) create mode 100644 target/linux/generic/patches-4.4/030-net_sched-introduce-qdisc_replace-helper.patch create mode 100644 target/linux/generic/patches-4.4/031-net_sched-update-hierarchical-backlog-too.patch create mode 100644 target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch diff --git a/target/linux/generic/patches-4.4/030-net_sched-introduce-qdisc_replace-helper.patch b/target/linux/generic/patches-4.4/030-net_sched-introduce-qdisc_replace-helper.patch new file mode 100644 index 0000000000..a3a601b346 --- /dev/null +++ b/target/linux/generic/patches-4.4/030-net_sched-introduce-qdisc_replace-helper.patch @@ -0,0 +1,237 @@ +From: WANG Cong +Date: Thu, 25 Feb 2016 14:55:00 -0800 +Subject: [PATCH] net_sched: introduce qdisc_replace() helper + +Remove nearly duplicated code and prepare for the following patch. + +Cc: Jamal Hadi Salim +Acked-by: Jamal Hadi Salim +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +--- + +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -698,6 +698,23 @@ static inline void qdisc_reset_queue(str + sch->qstats.backlog = 0; + } + ++static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new, ++ struct Qdisc **pold) ++{ ++ struct Qdisc *old; ++ ++ sch_tree_lock(sch); ++ old = *pold; ++ *pold = new; ++ if (old != NULL) { ++ qdisc_tree_decrease_qlen(old, old->q.qlen); ++ qdisc_reset(old); ++ } ++ sch_tree_unlock(sch); ++ ++ return old; ++} ++ + static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch, + struct sk_buff_head *list) + { +--- a/net/sched/sch_cbq.c ++++ b/net/sched/sch_cbq.c +@@ -1624,13 +1624,8 @@ static int cbq_graft(struct Qdisc *sch, + new->reshape_fail = cbq_reshape_fail; + #endif + } +- sch_tree_lock(sch); +- *old = cl->q; +- cl->q = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); + ++ *old = qdisc_replace(sch, new, &cl->q); + return 0; + } + +--- a/net/sched/sch_drr.c ++++ b/net/sched/sch_drr.c +@@ -226,11 +226,7 @@ static int drr_graft_class(struct Qdisc + new = &noop_qdisc; + } + +- sch_tree_lock(sch); +- drr_purge_queue(cl); +- *old = cl->qdisc; +- cl->qdisc = new; +- sch_tree_unlock(sch); ++ *old = qdisc_replace(sch, new, &cl->qdisc); + return 0; + } + +--- a/net/sched/sch_dsmark.c ++++ b/net/sched/sch_dsmark.c +@@ -73,13 +73,7 @@ static int dsmark_graft(struct Qdisc *sc + new = &noop_qdisc; + } + +- sch_tree_lock(sch); +- *old = p->q; +- p->q = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); +- ++ *old = qdisc_replace(sch, new, &p->q); + return 0; + } + +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -1215,11 +1215,7 @@ hfsc_graft_class(struct Qdisc *sch, unsi + new = &noop_qdisc; + } + +- sch_tree_lock(sch); +- hfsc_purge_queue(sch, cl); +- *old = cl->qdisc; +- cl->qdisc = new; +- sch_tree_unlock(sch); ++ *old = qdisc_replace(sch, new, &cl->qdisc); + return 0; + } + +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -1163,14 +1163,7 @@ static int htb_graft(struct Qdisc *sch, + cl->common.classid)) == NULL) + return -ENOBUFS; + +- sch_tree_lock(sch); +- *old = cl->un.leaf.q; +- cl->un.leaf.q = new; +- if (*old != NULL) { +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- } +- sch_tree_unlock(sch); ++ *old = qdisc_replace(sch, new, &cl->un.leaf.q); + return 0; + } + +--- a/net/sched/sch_multiq.c ++++ b/net/sched/sch_multiq.c +@@ -303,13 +303,7 @@ static int multiq_graft(struct Qdisc *sc + if (new == NULL) + new = &noop_qdisc; + +- sch_tree_lock(sch); +- *old = q->queues[band]; +- q->queues[band] = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); +- ++ *old = qdisc_replace(sch, new, &q->queues[band]); + return 0; + } + +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1037,15 +1037,7 @@ static int netem_graft(struct Qdisc *sch + { + struct netem_sched_data *q = qdisc_priv(sch); + +- sch_tree_lock(sch); +- *old = q->qdisc; +- q->qdisc = new; +- if (*old) { +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- } +- sch_tree_unlock(sch); +- ++ *old = qdisc_replace(sch, new, &q->qdisc); + return 0; + } + +--- a/net/sched/sch_prio.c ++++ b/net/sched/sch_prio.c +@@ -268,13 +268,7 @@ static int prio_graft(struct Qdisc *sch, + if (new == NULL) + new = &noop_qdisc; + +- sch_tree_lock(sch); +- *old = q->queues[band]; +- q->queues[band] = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); +- ++ *old = qdisc_replace(sch, new, &q->queues[band]); + return 0; + } + +--- a/net/sched/sch_qfq.c ++++ b/net/sched/sch_qfq.c +@@ -617,11 +617,7 @@ static int qfq_graft_class(struct Qdisc + new = &noop_qdisc; + } + +- sch_tree_lock(sch); +- qfq_purge_queue(cl); +- *old = cl->qdisc; +- cl->qdisc = new; +- sch_tree_unlock(sch); ++ *old = qdisc_replace(sch, new, &cl->qdisc); + return 0; + } + +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -313,12 +313,7 @@ static int red_graft(struct Qdisc *sch, + if (new == NULL) + new = &noop_qdisc; + +- sch_tree_lock(sch); +- *old = q->qdisc; +- q->qdisc = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); ++ *old = qdisc_replace(sch, new, &q->qdisc); + return 0; + } + +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -606,12 +606,7 @@ static int sfb_graft(struct Qdisc *sch, + if (new == NULL) + new = &noop_qdisc; + +- sch_tree_lock(sch); +- *old = q->qdisc; +- q->qdisc = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); ++ *old = qdisc_replace(sch, new, &q->qdisc); + return 0; + } + +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -502,13 +502,7 @@ static int tbf_graft(struct Qdisc *sch, + if (new == NULL) + new = &noop_qdisc; + +- sch_tree_lock(sch); +- *old = q->qdisc; +- q->qdisc = new; +- qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); +- qdisc_reset(*old); +- sch_tree_unlock(sch); +- ++ *old = qdisc_replace(sch, new, &q->qdisc); + return 0; + } + diff --git a/target/linux/generic/patches-4.4/031-net_sched-update-hierarchical-backlog-too.patch b/target/linux/generic/patches-4.4/031-net_sched-update-hierarchical-backlog-too.patch new file mode 100644 index 0000000000..eb34eea4a6 --- /dev/null +++ b/target/linux/generic/patches-4.4/031-net_sched-update-hierarchical-backlog-too.patch @@ -0,0 +1,647 @@ +From: WANG Cong +Date: Thu, 25 Feb 2016 14:55:01 -0800 +Subject: [PATCH] net_sched: update hierarchical backlog too + +When the bottom qdisc decides to, for example, drop some packet, +it calls qdisc_tree_decrease_qlen() to update the queue length +for all its ancestors, we need to update the backlog too to +keep the stats on root qdisc accurate. + +Cc: Jamal Hadi Salim +Acked-by: Jamal Hadi Salim +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +--- + +--- a/include/net/codel.h ++++ b/include/net/codel.h +@@ -162,12 +162,14 @@ struct codel_vars { + * struct codel_stats - contains codel shared variables and stats + * @maxpacket: largest packet we've seen so far + * @drop_count: temp count of dropped packets in dequeue() ++ * @drop_len: bytes of dropped packets in dequeue() + * ecn_mark: number of packets we ECN marked instead of dropping + * ce_mark: number of packets CE marked because sojourn time was above ce_threshold + */ + struct codel_stats { + u32 maxpacket; + u32 drop_count; ++ u32 drop_len; + u32 ecn_mark; + u32 ce_mark; + }; +@@ -308,6 +310,7 @@ static struct sk_buff *codel_dequeue(str + vars->rec_inv_sqrt); + goto end; + } ++ stats->drop_len += qdisc_pkt_len(skb); + qdisc_drop(skb, sch); + stats->drop_count++; + skb = dequeue_func(vars, sch); +@@ -330,6 +333,7 @@ static struct sk_buff *codel_dequeue(str + if (params->ecn && INET_ECN_set_ce(skb)) { + stats->ecn_mark++; + } else { ++ stats->drop_len += qdisc_pkt_len(skb); + qdisc_drop(skb, sch); + stats->drop_count++; + +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -396,7 +396,8 @@ struct Qdisc *dev_graft_qdisc(struct net + struct Qdisc *qdisc); + void qdisc_reset(struct Qdisc *qdisc); + void qdisc_destroy(struct Qdisc *qdisc); +-void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n); ++void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n, ++ unsigned int len); + struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + const struct Qdisc_ops *ops); + struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, +@@ -707,7 +708,7 @@ static inline struct Qdisc *qdisc_replac + old = *pold; + *pold = new; + if (old != NULL) { +- qdisc_tree_decrease_qlen(old, old->q.qlen); ++ qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog); + qdisc_reset(old); + } + sch_tree_unlock(sch); +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -744,14 +744,15 @@ static u32 qdisc_alloc_handle(struct net + return 0; + } + +-void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) ++void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n, ++ unsigned int len) + { + const struct Qdisc_class_ops *cops; + unsigned long cl; + u32 parentid; + int drops; + +- if (n == 0) ++ if (n == 0 && len == 0) + return; + drops = max_t(int, n, 0); + rcu_read_lock(); +@@ -774,11 +775,12 @@ void qdisc_tree_decrease_qlen(struct Qdi + cops->put(sch, cl); + } + sch->q.qlen -= n; ++ sch->qstats.backlog -= len; + __qdisc_qstats_drop(sch, drops); + } + rcu_read_unlock(); + } +-EXPORT_SYMBOL(qdisc_tree_decrease_qlen); ++EXPORT_SYMBOL(qdisc_tree_reduce_backlog); + + static void notify_and_destroy(struct net *net, struct sk_buff *skb, + struct nlmsghdr *n, u32 clid, +--- a/net/sched/sch_cbq.c ++++ b/net/sched/sch_cbq.c +@@ -1909,7 +1909,7 @@ static int cbq_delete(struct Qdisc *sch, + { + struct cbq_sched_data *q = qdisc_priv(sch); + struct cbq_class *cl = (struct cbq_class *)arg; +- unsigned int qlen; ++ unsigned int qlen, backlog; + + if (cl->filters || cl->children || cl == &q->link) + return -EBUSY; +@@ -1917,8 +1917,9 @@ static int cbq_delete(struct Qdisc *sch, + sch_tree_lock(sch); + + qlen = cl->q->q.qlen; ++ backlog = cl->q->qstats.backlog; + qdisc_reset(cl->q); +- qdisc_tree_decrease_qlen(cl->q, qlen); ++ qdisc_tree_reduce_backlog(cl->q, qlen, backlog); + + if (cl->next_alive) + cbq_deactivate_class(cl); +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdi + choke_zap_tail_holes(q); + + qdisc_qstats_backlog_dec(sch, skb); ++ qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); + qdisc_drop(skb, sch); +- qdisc_tree_decrease_qlen(sch, 1); + --sch->q.qlen; + } + +@@ -456,6 +456,7 @@ static int choke_change(struct Qdisc *sc + old = q->tab; + if (old) { + unsigned int oqlen = sch->q.qlen, tail = 0; ++ unsigned dropped = 0; + + while (q->head != q->tail) { + struct sk_buff *skb = q->tab[q->head]; +@@ -467,11 +468,12 @@ static int choke_change(struct Qdisc *sc + ntab[tail++] = skb; + continue; + } ++ dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); + --sch->q.qlen; + qdisc_drop(skb, sch); + } +- qdisc_tree_decrease_qlen(sch, oqlen - sch->q.qlen); ++ qdisc_tree_reduce_backlog(sch, oqlen - sch->q.qlen, dropped); + q->head = 0; + q->tail = tail; + } +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -79,12 +79,13 @@ static struct sk_buff *codel_qdisc_deque + + skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue); + +- /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, ++ /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, + * or HTB crashes. Defer it for next round. + */ + if (q->stats.drop_count && sch->q.qlen) { +- qdisc_tree_decrease_qlen(sch, q->stats.drop_count); ++ qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); + q->stats.drop_count = 0; ++ q->stats.drop_len = 0; + } + if (skb) + qdisc_bstats_update(sch, skb); +@@ -116,7 +117,7 @@ static int codel_change(struct Qdisc *sc + { + struct codel_sched_data *q = qdisc_priv(sch); + struct nlattr *tb[TCA_CODEL_MAX + 1]; +- unsigned int qlen; ++ unsigned int qlen, dropped = 0; + int err; + + if (!opt) +@@ -156,10 +157,11 @@ static int codel_change(struct Qdisc *sc + while (sch->q.qlen > sch->limit) { + struct sk_buff *skb = __skb_dequeue(&sch->q); + ++ dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); + qdisc_drop(skb, sch); + } +- qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); ++ qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + + sch_tree_unlock(sch); + return 0; +--- a/net/sched/sch_drr.c ++++ b/net/sched/sch_drr.c +@@ -53,9 +53,10 @@ static struct drr_class *drr_find_class( + static void drr_purge_queue(struct drr_class *cl) + { + unsigned int len = cl->qdisc->q.qlen; ++ unsigned int backlog = cl->qdisc->qstats.backlog; + + qdisc_reset(cl->qdisc); +- qdisc_tree_decrease_qlen(cl->qdisc, len); ++ qdisc_tree_reduce_backlog(cl->qdisc, len, backlog); + } + + static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = { +--- a/net/sched/sch_fq.c ++++ b/net/sched/sch_fq.c +@@ -662,6 +662,7 @@ static int fq_change(struct Qdisc *sch, + struct fq_sched_data *q = qdisc_priv(sch); + struct nlattr *tb[TCA_FQ_MAX + 1]; + int err, drop_count = 0; ++ unsigned drop_len = 0; + u32 fq_log; + + if (!opt) +@@ -736,10 +737,11 @@ static int fq_change(struct Qdisc *sch, + + if (!skb) + break; ++ drop_len += qdisc_pkt_len(skb); + kfree_skb(skb); + drop_count++; + } +- qdisc_tree_decrease_qlen(sch, drop_count); ++ qdisc_tree_reduce_backlog(sch, drop_count, drop_len); + + sch_tree_unlock(sch); + return err; +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -175,7 +175,7 @@ static unsigned int fq_codel_qdisc_drop( + static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { + struct fq_codel_sched_data *q = qdisc_priv(sch); +- unsigned int idx; ++ unsigned int idx, prev_backlog; + struct fq_codel_flow *flow; + int uninitialized_var(ret); + +@@ -203,6 +203,7 @@ static int fq_codel_enqueue(struct sk_bu + if (++sch->q.qlen <= sch->limit) + return NET_XMIT_SUCCESS; + ++ prev_backlog = sch->qstats.backlog; + q->drop_overlimit++; + /* Return Congestion Notification only if we dropped a packet + * from this flow. +@@ -211,7 +212,7 @@ static int fq_codel_enqueue(struct sk_bu + return NET_XMIT_CN; + + /* As we dropped a packet, better let upper stack know this */ +- qdisc_tree_decrease_qlen(sch, 1); ++ qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog); + return NET_XMIT_SUCCESS; + } + +@@ -241,6 +242,7 @@ static struct sk_buff *fq_codel_dequeue( + struct fq_codel_flow *flow; + struct list_head *head; + u32 prev_drop_count, prev_ecn_mark; ++ unsigned int prev_backlog; + + begin: + head = &q->new_flows; +@@ -259,6 +261,7 @@ begin: + + prev_drop_count = q->cstats.drop_count; + prev_ecn_mark = q->cstats.ecn_mark; ++ prev_backlog = sch->qstats.backlog; + + skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats, + dequeue); +@@ -276,12 +279,14 @@ begin: + } + qdisc_bstats_update(sch, skb); + flow->deficit -= qdisc_pkt_len(skb); +- /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, ++ /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, + * or HTB crashes. Defer it for next round. + */ + if (q->cstats.drop_count && sch->q.qlen) { +- qdisc_tree_decrease_qlen(sch, q->cstats.drop_count); ++ qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, ++ q->cstats.drop_len); + q->cstats.drop_count = 0; ++ q->cstats.drop_len = 0; + } + return skb; + } +@@ -372,11 +377,13 @@ static int fq_codel_change(struct Qdisc + while (sch->q.qlen > sch->limit) { + struct sk_buff *skb = fq_codel_dequeue(sch); + ++ q->cstats.drop_len += qdisc_pkt_len(skb); + kfree_skb(skb); + q->cstats.drop_count++; + } +- qdisc_tree_decrease_qlen(sch, q->cstats.drop_count); ++ qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len); + q->cstats.drop_count = 0; ++ q->cstats.drop_len = 0; + + sch_tree_unlock(sch); + return 0; +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -895,9 +895,10 @@ static void + hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl) + { + unsigned int len = cl->qdisc->q.qlen; ++ unsigned int backlog = cl->qdisc->qstats.backlog; + + qdisc_reset(cl->qdisc); +- qdisc_tree_decrease_qlen(cl->qdisc, len); ++ qdisc_tree_reduce_backlog(cl->qdisc, len, backlog); + } + + static void +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -382,6 +382,7 @@ static int hhf_enqueue(struct sk_buff *s + struct hhf_sched_data *q = qdisc_priv(sch); + enum wdrr_bucket_idx idx; + struct wdrr_bucket *bucket; ++ unsigned int prev_backlog; + + idx = hhf_classify(skb, sch); + +@@ -409,6 +410,7 @@ static int hhf_enqueue(struct sk_buff *s + if (++sch->q.qlen <= sch->limit) + return NET_XMIT_SUCCESS; + ++ prev_backlog = sch->qstats.backlog; + q->drop_overlimit++; + /* Return Congestion Notification only if we dropped a packet from this + * bucket. +@@ -417,7 +419,7 @@ static int hhf_enqueue(struct sk_buff *s + return NET_XMIT_CN; + + /* As we dropped a packet, better let upper stack know this. */ +- qdisc_tree_decrease_qlen(sch, 1); ++ qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog); + return NET_XMIT_SUCCESS; + } + +@@ -527,7 +529,7 @@ static int hhf_change(struct Qdisc *sch, + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct nlattr *tb[TCA_HHF_MAX + 1]; +- unsigned int qlen; ++ unsigned int qlen, prev_backlog; + int err; + u64 non_hh_quantum; + u32 new_quantum = q->quantum; +@@ -577,12 +579,14 @@ static int hhf_change(struct Qdisc *sch, + } + + qlen = sch->q.qlen; ++ prev_backlog = sch->qstats.backlog; + while (sch->q.qlen > sch->limit) { + struct sk_buff *skb = hhf_dequeue(sch); + + kfree_skb(skb); + } +- qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); ++ qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, ++ prev_backlog - sch->qstats.backlog); + + sch_tree_unlock(sch); + return 0; +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -1265,7 +1265,6 @@ static int htb_delete(struct Qdisc *sch, + { + struct htb_sched *q = qdisc_priv(sch); + struct htb_class *cl = (struct htb_class *)arg; +- unsigned int qlen; + struct Qdisc *new_q = NULL; + int last_child = 0; + +@@ -1285,9 +1284,11 @@ static int htb_delete(struct Qdisc *sch, + sch_tree_lock(sch); + + if (!cl->level) { +- qlen = cl->un.leaf.q->q.qlen; ++ unsigned int qlen = cl->un.leaf.q->q.qlen; ++ unsigned int backlog = cl->un.leaf.q->qstats.backlog; ++ + qdisc_reset(cl->un.leaf.q); +- qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); ++ qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog); + } + + /* delete from hash and active; remainder in destroy_class */ +@@ -1421,10 +1422,11 @@ static int htb_change_class(struct Qdisc + sch_tree_lock(sch); + if (parent && !parent->level) { + unsigned int qlen = parent->un.leaf.q->q.qlen; ++ unsigned int backlog = parent->un.leaf.q->qstats.backlog; + + /* turn parent into inner node */ + qdisc_reset(parent->un.leaf.q); +- qdisc_tree_decrease_qlen(parent->un.leaf.q, qlen); ++ qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog); + qdisc_destroy(parent->un.leaf.q); + if (parent->prio_activity) + htb_deactivate(q, parent); +--- a/net/sched/sch_multiq.c ++++ b/net/sched/sch_multiq.c +@@ -218,7 +218,8 @@ static int multiq_tune(struct Qdisc *sch + if (q->queues[i] != &noop_qdisc) { + struct Qdisc *child = q->queues[i]; + q->queues[i] = &noop_qdisc; +- qdisc_tree_decrease_qlen(child, child->q.qlen); ++ qdisc_tree_reduce_backlog(child, child->q.qlen, ++ child->qstats.backlog); + qdisc_destroy(child); + } + } +@@ -238,8 +239,9 @@ static int multiq_tune(struct Qdisc *sch + q->queues[i] = child; + + if (old != &noop_qdisc) { +- qdisc_tree_decrease_qlen(old, +- old->q.qlen); ++ qdisc_tree_reduce_backlog(old, ++ old->q.qlen, ++ old->qstats.backlog); + qdisc_destroy(old); + } + sch_tree_unlock(sch); +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -598,7 +598,8 @@ deliver: + if (unlikely(err != NET_XMIT_SUCCESS)) { + if (net_xmit_drop_count(err)) { + qdisc_qstats_drop(sch); +- qdisc_tree_decrease_qlen(sch, 1); ++ qdisc_tree_reduce_backlog(sch, 1, ++ qdisc_pkt_len(skb)); + } + } + goto tfifo_dequeue; +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -183,7 +183,7 @@ static int pie_change(struct Qdisc *sch, + { + struct pie_sched_data *q = qdisc_priv(sch); + struct nlattr *tb[TCA_PIE_MAX + 1]; +- unsigned int qlen; ++ unsigned int qlen, dropped = 0; + int err; + + if (!opt) +@@ -232,10 +232,11 @@ static int pie_change(struct Qdisc *sch, + while (sch->q.qlen > sch->limit) { + struct sk_buff *skb = __skb_dequeue(&sch->q); + ++ dropped += qdisc_pkt_len(skb); + qdisc_qstats_backlog_dec(sch, skb); + qdisc_drop(skb, sch); + } +- qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); ++ qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + + sch_tree_unlock(sch); + return 0; +--- a/net/sched/sch_prio.c ++++ b/net/sched/sch_prio.c +@@ -191,7 +191,7 @@ static int prio_tune(struct Qdisc *sch, + struct Qdisc *child = q->queues[i]; + q->queues[i] = &noop_qdisc; + if (child != &noop_qdisc) { +- qdisc_tree_decrease_qlen(child, child->q.qlen); ++ qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog); + qdisc_destroy(child); + } + } +@@ -210,8 +210,9 @@ static int prio_tune(struct Qdisc *sch, + q->queues[i] = child; + + if (old != &noop_qdisc) { +- qdisc_tree_decrease_qlen(old, +- old->q.qlen); ++ qdisc_tree_reduce_backlog(old, ++ old->q.qlen, ++ old->qstats.backlog); + qdisc_destroy(old); + } + sch_tree_unlock(sch); +--- a/net/sched/sch_qfq.c ++++ b/net/sched/sch_qfq.c +@@ -220,9 +220,10 @@ static struct qfq_class *qfq_find_class( + static void qfq_purge_queue(struct qfq_class *cl) + { + unsigned int len = cl->qdisc->q.qlen; ++ unsigned int backlog = cl->qdisc->qstats.backlog; + + qdisc_reset(cl->qdisc); +- qdisc_tree_decrease_qlen(cl->qdisc, len); ++ qdisc_tree_reduce_backlog(cl->qdisc, len, backlog); + } + + static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = { +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -210,7 +210,8 @@ static int red_change(struct Qdisc *sch, + q->flags = ctl->flags; + q->limit = ctl->limit; + if (child) { +- qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); ++ qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, ++ q->qdisc->qstats.backlog); + qdisc_destroy(q->qdisc); + q->qdisc = child; + } +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -510,7 +510,8 @@ static int sfb_change(struct Qdisc *sch, + + sch_tree_lock(sch); + +- qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); ++ qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, ++ q->qdisc->qstats.backlog); + qdisc_destroy(q->qdisc); + q->qdisc = child; + +--- a/net/sched/sch_sfq.c ++++ b/net/sched/sch_sfq.c +@@ -346,7 +346,7 @@ static int + sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { + struct sfq_sched_data *q = qdisc_priv(sch); +- unsigned int hash; ++ unsigned int hash, dropped; + sfq_index x, qlen; + struct sfq_slot *slot; + int uninitialized_var(ret); +@@ -461,7 +461,7 @@ enqueue: + return NET_XMIT_SUCCESS; + + qlen = slot->qlen; +- sfq_drop(sch); ++ dropped = sfq_drop(sch); + /* Return Congestion Notification only if we dropped a packet + * from this flow. + */ +@@ -469,7 +469,7 @@ enqueue: + return NET_XMIT_CN; + + /* As we dropped a packet, better let upper stack know this */ +- qdisc_tree_decrease_qlen(sch, 1); ++ qdisc_tree_reduce_backlog(sch, 1, dropped); + return NET_XMIT_SUCCESS; + } + +@@ -537,6 +537,7 @@ static void sfq_rehash(struct Qdisc *sch + struct sfq_slot *slot; + struct sk_buff_head list; + int dropped = 0; ++ unsigned int drop_len = 0; + + __skb_queue_head_init(&list); + +@@ -565,6 +566,7 @@ static void sfq_rehash(struct Qdisc *sch + if (x >= SFQ_MAX_FLOWS) { + drop: + qdisc_qstats_backlog_dec(sch, skb); ++ drop_len += qdisc_pkt_len(skb); + kfree_skb(skb); + dropped++; + continue; +@@ -594,7 +596,7 @@ drop: + } + } + sch->q.qlen -= dropped; +- qdisc_tree_decrease_qlen(sch, dropped); ++ qdisc_tree_reduce_backlog(sch, dropped, drop_len); + } + + static void sfq_perturbation(unsigned long arg) +@@ -618,7 +620,7 @@ static int sfq_change(struct Qdisc *sch, + struct sfq_sched_data *q = qdisc_priv(sch); + struct tc_sfq_qopt *ctl = nla_data(opt); + struct tc_sfq_qopt_v1 *ctl_v1 = NULL; +- unsigned int qlen; ++ unsigned int qlen, dropped = 0; + struct red_parms *p = NULL; + + if (opt->nla_len < nla_attr_size(sizeof(*ctl))) +@@ -667,8 +669,8 @@ static int sfq_change(struct Qdisc *sch, + + qlen = sch->q.qlen; + while (sch->q.qlen > q->limit) +- sfq_drop(sch); +- qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); ++ dropped += sfq_drop(sch); ++ qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped); + + del_timer(&q->perturb_timer); + if (q->perturb_period) { +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -160,6 +160,7 @@ static int tbf_segment(struct sk_buff *s + struct tbf_sched_data *q = qdisc_priv(sch); + struct sk_buff *segs, *nskb; + netdev_features_t features = netif_skb_features(skb); ++ unsigned int len = 0, prev_len = qdisc_pkt_len(skb); + int ret, nb; + + segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); +@@ -172,6 +173,7 @@ static int tbf_segment(struct sk_buff *s + nskb = segs->next; + segs->next = NULL; + qdisc_skb_cb(segs)->pkt_len = segs->len; ++ len += segs->len; + ret = qdisc_enqueue(segs, q->qdisc); + if (ret != NET_XMIT_SUCCESS) { + if (net_xmit_drop_count(ret)) +@@ -183,7 +185,7 @@ static int tbf_segment(struct sk_buff *s + } + sch->q.qlen += nb; + if (nb > 1) +- qdisc_tree_decrease_qlen(sch, 1 - nb); ++ qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len); + consume_skb(skb); + return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP; + } +@@ -399,7 +401,8 @@ static int tbf_change(struct Qdisc *sch, + + sch_tree_lock(sch); + if (child) { +- qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); ++ qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, ++ q->qdisc->qstats.backlog); + qdisc_destroy(q->qdisc); + q->qdisc = child; + } diff --git a/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch b/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch new file mode 100644 index 0000000000..94c9c7fe27 --- /dev/null +++ b/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch @@ -0,0 +1,189 @@ +From: Eric Dumazet +Date: Sun, 1 May 2016 16:47:26 -0700 +Subject: [PATCH] fq_codel: add batch ability to fq_codel_drop() + +In presence of inelastic flows and stress, we can call +fq_codel_drop() for every packet entering fq_codel qdisc. + +fq_codel_drop() is quite expensive, as it does a linear scan +of 4 KB of memory to find a fat flow. +Once found, it drops the oldest packet of this flow. + +Instead of dropping a single packet, try to drop 50% of the backlog +of this fat flow, with a configurable limit of 64 packets per round. + +TCA_FQ_CODEL_DROP_BATCH_SIZE is the new attribute to make this +limit configurable. + +With this strategy the 4 KB search is amortized to a single cache line +per drop [1], so fq_codel_drop() no longer appears at the top of kernel +profile in presence of few inelastic flows. + +[1] Assuming a 64byte cache line, and 1024 buckets + +Signed-off-by: Eric Dumazet +Reported-by: Dave Taht +Cc: Jonathan Morton +Acked-by: Jesper Dangaard Brouer +Acked-by: Dave Taht +Signed-off-by: David S. Miller +--- + +--- a/include/uapi/linux/pkt_sched.h ++++ b/include/uapi/linux/pkt_sched.h +@@ -711,6 +711,7 @@ enum { + TCA_FQ_CODEL_FLOWS, + TCA_FQ_CODEL_QUANTUM, + TCA_FQ_CODEL_CE_THRESHOLD, ++ TCA_FQ_CODEL_DROP_BATCH_SIZE, + __TCA_FQ_CODEL_MAX + }; + +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -57,6 +57,7 @@ struct fq_codel_sched_data { + u32 flows_cnt; /* number of flows */ + u32 perturbation; /* hash perturbation */ + u32 quantum; /* psched_mtu(qdisc_dev(sch)); */ ++ u32 drop_batch_size; + struct codel_params cparams; + struct codel_stats cstats; + u32 drop_overlimit; +@@ -133,17 +134,20 @@ static inline void flow_queue_add(struct + skb->next = NULL; + } + +-static unsigned int fq_codel_drop(struct Qdisc *sch) ++static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets) + { + struct fq_codel_sched_data *q = qdisc_priv(sch); + struct sk_buff *skb; + unsigned int maxbacklog = 0, idx = 0, i, len; + struct fq_codel_flow *flow; ++ unsigned int threshold; + +- /* Queue is full! Find the fat flow and drop packet from it. ++ /* Queue is full! Find the fat flow and drop packet(s) from it. + * This might sound expensive, but with 1024 flows, we scan + * 4KB of memory, and we dont need to handle a complex tree + * in fast path (packet queue/enqueue) with many cache misses. ++ * In stress mode, we'll try to drop 64 packets from the flow, ++ * amortizing this linear lookup to one cache line per drop. + */ + for (i = 0; i < q->flows_cnt; i++) { + if (q->backlogs[i] > maxbacklog) { +@@ -151,15 +155,24 @@ static unsigned int fq_codel_drop(struct + idx = i; + } + } ++ ++ /* Our goal is to drop half of this fat flow backlog */ ++ threshold = maxbacklog >> 1; ++ + flow = &q->flows[idx]; +- skb = dequeue_head(flow); +- len = qdisc_pkt_len(skb); ++ len = 0; ++ i = 0; ++ do { ++ skb = dequeue_head(flow); ++ len += qdisc_pkt_len(skb); ++ kfree_skb(skb); ++ } while (++i < max_packets && len < threshold); ++ ++ flow->dropped += i; + q->backlogs[idx] -= len; +- sch->q.qlen--; +- qdisc_qstats_drop(sch); +- qdisc_qstats_backlog_dec(sch, skb); +- kfree_skb(skb); +- flow->dropped++; ++ sch->qstats.drops += i; ++ sch->qstats.backlog -= len; ++ sch->q.qlen -= i; + return idx; + } + +@@ -168,14 +181,14 @@ static unsigned int fq_codel_qdisc_drop( + unsigned int prev_backlog; + + prev_backlog = sch->qstats.backlog; +- fq_codel_drop(sch); ++ fq_codel_drop(sch, 1U); + return prev_backlog - sch->qstats.backlog; + } + + static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) + { + struct fq_codel_sched_data *q = qdisc_priv(sch); +- unsigned int idx, prev_backlog; ++ unsigned int idx, prev_backlog, prev_qlen; + struct fq_codel_flow *flow; + int uninitialized_var(ret); + +@@ -204,16 +217,22 @@ static int fq_codel_enqueue(struct sk_bu + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; +- /* Return Congestion Notification only if we dropped a packet +- * from this flow. ++ prev_qlen = sch->q.qlen; ++ ++ /* 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 ++ * with a 64 packets limit to not add a too big cpu spike here. + */ +- if (fq_codel_drop(sch) == idx) +- return NET_XMIT_CN; ++ ret = fq_codel_drop(sch, q->drop_batch_size); + +- /* As we dropped a packet, better let upper stack know this */ +- qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog); +- return NET_XMIT_SUCCESS; ++ q->drop_overlimit += 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); ++ ++ return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS; + } + + /* This is the specific function called from codel_dequeue() +@@ -323,6 +342,7 @@ static const struct nla_policy fq_codel_ + [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 }, + [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 }, + [TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 }, ++ [TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NLA_U32 }, + }; + + static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) +@@ -374,6 +394,9 @@ static int fq_codel_change(struct Qdisc + if (tb[TCA_FQ_CODEL_QUANTUM]) + q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM])); + ++ if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]) ++ q->drop_batch_size = min(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])); ++ + while (sch->q.qlen > sch->limit) { + struct sk_buff *skb = fq_codel_dequeue(sch); + +@@ -419,6 +442,7 @@ static int fq_codel_init(struct Qdisc *s + + sch->limit = 10*1024; + q->flows_cnt = 1024; ++ q->drop_batch_size = 64; + q->quantum = psched_mtu(qdisc_dev(sch)); + q->perturbation = prandom_u32(); + INIT_LIST_HEAD(&q->new_flows); +@@ -476,6 +500,8 @@ static int fq_codel_dump(struct Qdisc *s + q->cparams.ecn) || + nla_put_u32(skb, TCA_FQ_CODEL_QUANTUM, + q->quantum) || ++ nla_put_u32(skb, TCA_FQ_CODEL_DROP_BATCH_SIZE, ++ q->drop_batch_size) || + nla_put_u32(skb, TCA_FQ_CODEL_FLOWS, + q->flows_cnt)) + goto nla_put_failure; diff --git a/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch index a69d197e62..4a056c8bb9 100644 --- a/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch +++ b/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch @@ -284,15 +284,15 @@ Signed-off-by: Yousong Zhou + EXPORT(kexec_argv_buf) + .skip KEXEC_COMMAND_LINE_SIZE + .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE -+ -+kexec_argv: -+ EXPORT(kexec_argv) -+ .skip KEXEC_ARGV_SIZE -+ .size kexec_argv, KEXEC_ARGV_SIZE -relocate_new_kernel_size: - EXPORT(relocate_new_kernel_size) - PTR relocate_new_kernel_end - relocate_new_kernel - .size relocate_new_kernel_size, PTRSIZE ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE ++ +kexec_relocate_new_kernel_end: + EXPORT(kexec_relocate_new_kernel_end) diff --git a/target/linux/generic/patches-4.4/531-debloat_lzma.patch b/target/linux/generic/patches-4.4/531-debloat_lzma.patch index aa3c498016..bbf2b75304 100644 --- a/target/linux/generic/patches-4.4/531-debloat_lzma.patch +++ b/target/linux/generic/patches-4.4/531-debloat_lzma.patch @@ -219,26 +219,26 @@ { UInt32 dicSize; Byte d; -@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma +@@ -935,33 +883,11 @@ static SRes LzmaDec_AllocateProbs2(CLzma return SZ_OK; } -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -+static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) - { - CLzmaProps propNew; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); -@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p, - p->prop = propNew; - return SZ_OK; - } -- --SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -{ - CLzmaProps propNew; -- SizeT dicBufSize; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)); - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); +- p->prop = propNew; +- return SZ_OK; +-} +- +-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) + { + CLzmaProps propNew; +- SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - dicBufSize = propNew.dicSize; - if (p->dic == 0 || dicBufSize != p->dicBufSize) - { @@ -251,12 +251,9 @@ - } - } - p->dicBufSize = dicBufSize; -- p->prop = propNew; -- return SZ_OK; --} - - SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + p->prop = propNew; + return SZ_OK; + } --- a/include/linux/lzma/LzmaEnc.h +++ b/include/linux/lzma/LzmaEnc.h @@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps diff --git a/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch index f729f38f11..7232b93de5 100644 --- a/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch +++ b/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch @@ -382,8 +382,6 @@ Implement optinal multicast->unicast conversion for igmp snooping - port = (unsigned long)lport > (unsigned long)rport ? - lport : rport; -- -- prev = maybe_deliver(prev, port, skb, __packet_hook); + if ((unsigned long)lport > (unsigned long)rport) { + port = lport; + addr = p->unicast ? p->eth_addr : NULL; @@ -391,7 +389,8 @@ Implement optinal multicast->unicast conversion for igmp snooping + port = rport; + addr = NULL; + } -+ + +- prev = maybe_deliver(prev, port, skb, __packet_hook); + if (addr) + prev = maybe_deliver_addr(prev, port, skb, addr, + __packet_hook); diff --git a/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch index bee4fcd86b..bbf281009d 100644 --- a/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch +++ b/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch @@ -1,6 +1,6 @@ --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c -@@ -410,8 +410,8 @@ static int fq_codel_init(struct Qdisc *s +@@ -440,8 +440,8 @@ static int fq_codel_init(struct Qdisc *s struct fq_codel_sched_data *q = qdisc_priv(sch); int i; @@ -8,6 +8,6 @@ - q->flows_cnt = 1024; + sch->limit = 1024; + q->flows_cnt = 128; + q->drop_batch_size = 64; q->quantum = psched_mtu(qdisc_dev(sch)); q->perturbation = prandom_u32(); - INIT_LIST_HEAD(&q->new_flows); diff --git a/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch index 45a8d68367..cb3bb2f28d 100644 --- a/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch +++ b/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch @@ -1,6 +1,6 @@ --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c -@@ -198,7 +198,6 @@ static int fq_codel_enqueue(struct sk_bu +@@ -211,7 +211,6 @@ static int fq_codel_enqueue(struct sk_bu list_add_tail(&flow->flowchain, &q->new_flows); q->new_flow_count++; flow->deficit = q->quantum; diff --git a/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch index 6910cfa0e6..37b601a443 100644 --- a/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch +++ b/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch @@ -13,7 +13,7 @@ device, it has to decide which ones to send first, which ones to --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c -@@ -621,7 +621,7 @@ static const struct Qdisc_class_ops fq_c +@@ -654,7 +654,7 @@ static const struct Qdisc_class_ops fq_c .walk = fq_codel_walk, }; @@ -22,7 +22,7 @@ .cl_ops = &fq_codel_class_ops, .id = "fq_codel", .priv_size = sizeof(struct fq_codel_sched_data), -@@ -637,6 +637,7 @@ static struct Qdisc_ops fq_codel_qdisc_o +@@ -670,6 +670,7 @@ static struct Qdisc_ops fq_codel_qdisc_o .dump_stats = fq_codel_dump_stats, .owner = THIS_MODULE, }; @@ -84,7 +84,7 @@ if (qdisc == NULL) { --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c -@@ -1946,7 +1946,7 @@ static int __init pktsched_init(void) +@@ -1948,7 +1948,7 @@ static int __init pktsched_init(void) return err; } -- 2.25.1