diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_api.c | 34 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 7 | ||||
-rw-r--r-- | net/sched/sch_prio.c | 22 |
3 files changed, 62 insertions, 1 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 5e9ab343c062..4ee2e9a3d12e 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1177,6 +1177,40 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n) } /* + * enable/disable flow on qdisc. + */ +int +tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int enable_flow) +{ + struct Qdisc *q; + int qdisc_len = 0; + struct __qdisc_change_req { + struct nlattr attr; + struct tc_prio_qopt data; + } req = { + .attr = {sizeof(struct __qdisc_change_req), TCA_OPTIONS}, + .data = {3, {1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1} + }; + + /* override flow bit */ + req.data.enable_flow = enable_flow; + + /* look up using tcm handle */ + q = qdisc_lookup(dev, tcm_handle); + + /* call registered change function */ + if (likely(q && q->ops)) { + if (likely(q->ops->change)) { + qdisc_len = q->q.qlen; + if (q->ops->change(q, &req.attr) != 0) + pr_err("%s(): qdisc change failed", __func__); + } + } + return qdisc_len; +} +EXPORT_SYMBOL(tc_qdisc_flow_control); + +/* * Create/change qdisc. */ diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 10c05fa0e6b3..aa9ed0440de2 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -303,7 +303,12 @@ static void dev_watchdog(unsigned long arg) } } - if (some_queue_timedout) { + /* The noise is pissing off our CI and upstream doesn't + * move on the bug report: + * + * https://bugzilla.kernel.org/show_bug.cgi?id=196399 + */ + if (some_queue_timedout && 0) { WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n", dev->name, netdev_drivername(dev), i); dev->netdev_ops->ndo_tx_timeout(dev); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 40ed14433f2c..81ea3a87bc04 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -18,6 +18,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/skbuff.h> +#include <linux/netdevice.h> #include <net/netlink.h> #include <net/pkt_sched.h> @@ -27,6 +28,7 @@ struct prio_sched_data { struct tcf_proto __rcu *filter_list; u8 prio2band[TC_PRIO_MAX+1]; struct Qdisc *queues[TCQ_PRIO_BANDS]; + u8 enable_flow; }; @@ -99,6 +101,9 @@ static struct sk_buff *prio_peek(struct Qdisc *sch) struct prio_sched_data *q = qdisc_priv(sch); int prio; + if (!q->enable_flow) + return NULL; + for (prio = 0; prio < q->bands; prio++) { struct Qdisc *qdisc = q->queues[prio]; struct sk_buff *skb = qdisc->ops->peek(qdisc); @@ -113,6 +118,9 @@ static struct sk_buff *prio_dequeue(struct Qdisc *sch) struct prio_sched_data *q = qdisc_priv(sch); int prio; + if (!q->enable_flow) + return NULL; + for (prio = 0; prio < q->bands; prio++) { struct Qdisc *qdisc = q->queues[prio]; struct sk_buff *skb = qdisc_dequeue_peeked(qdisc); @@ -156,6 +164,7 @@ prio_reset(struct Qdisc *sch) qdisc_reset(q->queues[prio]); sch->qstats.backlog = 0; sch->q.qlen = 0; + q->enable_flow = 1; } static void @@ -174,6 +183,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) struct prio_sched_data *q = qdisc_priv(sch); struct tc_prio_qopt *qopt; int i; + int flow_change = 0; if (nla_len(opt) < sizeof(*qopt)) return -EINVAL; @@ -188,6 +198,10 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) } sch_tree_lock(sch); + if (q->enable_flow != qopt->enable_flow) { + q->enable_flow = qopt->enable_flow; + flow_change = 1; + } q->bands = qopt->bands; memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); @@ -223,6 +237,13 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) } } } + + /* Schedule qdisc when flow re-enabled */ + if (flow_change && q->enable_flow) { + if (!test_bit(__QDISC_STATE_DEACTIVATED, + &sch->state)) + __netif_schedule(qdisc_root(sch)); + } return 0; } @@ -252,6 +273,7 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) struct tc_prio_qopt opt; opt.bands = q->bands; + opt.enable_flow = q->enable_flow; memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX + 1); if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) |