summaryrefslogtreecommitdiff
path: root/net/sched/sch_prio.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_prio.c')
-rw-r--r--net/sched/sch_prio.c22
1 files changed, 22 insertions, 0 deletions
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))