Loading include/net/pkt_sched.h +2 −0 Original line number Diff line number Diff line Loading @@ -133,6 +133,8 @@ static inline __be16 tc_skb_protocol(const struct sk_buff *skb) return skb->protocol; } extern int tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int flow_enable); /* Calculate maximal size of packet seen by hard_start_xmit routine of this device. */ Loading include/uapi/linux/pkt_sched.h +3 −0 Original line number Diff line number Diff line Loading @@ -147,8 +147,11 @@ struct tc_skbprio_qopt { struct tc_prio_qopt { int bands; /* Number of bands */ __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ __u8 enable_flow; /* Enable dequeue */ }; #define TCQ_PRIO_FLOW_CONTROL 1 /* MULTIQ section */ struct tc_multiq_qopt { Loading net/sched/sch_api.c +34 −0 Original line number Diff line number Diff line Loading @@ -1404,6 +1404,40 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, return 0; } /* * 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, NULL)) pr_err("%s(): qdisc change failed\n", __func__); } } return qdisc_len; } EXPORT_SYMBOL(tc_qdisc_flow_control); /* * Create/change qdisc. */ Loading net/sched/sch_prio.c +21 −0 Original line number Diff line number Diff line Loading @@ -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> #include <net/pkt_cls.h> Loading @@ -28,6 +29,7 @@ struct prio_sched_data { struct tcf_block *block; u8 prio2band[TC_PRIO_MAX+1]; struct Qdisc *queues[TCQ_PRIO_BANDS]; u8 enable_flow; }; Loading Loading @@ -102,6 +104,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); Loading @@ -116,6 +121,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); Loading @@ -140,6 +148,7 @@ prio_reset(struct Qdisc *sch) qdisc_reset(q->queues[prio]); sch->qstats.backlog = 0; sch->q.qlen = 0; q->enable_flow = 1; } static int prio_offload(struct Qdisc *sch, struct tc_prio_qopt *qopt) Loading Loading @@ -185,6 +194,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, struct Qdisc *queues[TCQ_PRIO_BANDS]; int oldbands = q->bands, i; struct tc_prio_qopt *qopt; int flow_change = 0; if (nla_len(opt) < sizeof(*qopt)) return -EINVAL; Loading Loading @@ -212,6 +222,10 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, prio_offload(sch, qopt); 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); Loading @@ -230,6 +244,12 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, } sch_tree_unlock(sch); /* 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; } Loading Loading @@ -288,6 +308,7 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) int err; opt.bands = q->bands; opt.enable_flow = q->enable_flow; memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX + 1); err = prio_dump_offload(sch); Loading Loading
include/net/pkt_sched.h +2 −0 Original line number Diff line number Diff line Loading @@ -133,6 +133,8 @@ static inline __be16 tc_skb_protocol(const struct sk_buff *skb) return skb->protocol; } extern int tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int flow_enable); /* Calculate maximal size of packet seen by hard_start_xmit routine of this device. */ Loading
include/uapi/linux/pkt_sched.h +3 −0 Original line number Diff line number Diff line Loading @@ -147,8 +147,11 @@ struct tc_skbprio_qopt { struct tc_prio_qopt { int bands; /* Number of bands */ __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ __u8 enable_flow; /* Enable dequeue */ }; #define TCQ_PRIO_FLOW_CONTROL 1 /* MULTIQ section */ struct tc_multiq_qopt { Loading
net/sched/sch_api.c +34 −0 Original line number Diff line number Diff line Loading @@ -1404,6 +1404,40 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, return 0; } /* * 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, NULL)) pr_err("%s(): qdisc change failed\n", __func__); } } return qdisc_len; } EXPORT_SYMBOL(tc_qdisc_flow_control); /* * Create/change qdisc. */ Loading
net/sched/sch_prio.c +21 −0 Original line number Diff line number Diff line Loading @@ -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> #include <net/pkt_cls.h> Loading @@ -28,6 +29,7 @@ struct prio_sched_data { struct tcf_block *block; u8 prio2band[TC_PRIO_MAX+1]; struct Qdisc *queues[TCQ_PRIO_BANDS]; u8 enable_flow; }; Loading Loading @@ -102,6 +104,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); Loading @@ -116,6 +121,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); Loading @@ -140,6 +148,7 @@ prio_reset(struct Qdisc *sch) qdisc_reset(q->queues[prio]); sch->qstats.backlog = 0; sch->q.qlen = 0; q->enable_flow = 1; } static int prio_offload(struct Qdisc *sch, struct tc_prio_qopt *qopt) Loading Loading @@ -185,6 +194,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, struct Qdisc *queues[TCQ_PRIO_BANDS]; int oldbands = q->bands, i; struct tc_prio_qopt *qopt; int flow_change = 0; if (nla_len(opt) < sizeof(*qopt)) return -EINVAL; Loading Loading @@ -212,6 +222,10 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, prio_offload(sch, qopt); 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); Loading @@ -230,6 +244,12 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, } sch_tree_unlock(sch); /* 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; } Loading Loading @@ -288,6 +308,7 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) int err; opt.bands = q->bands; opt.enable_flow = q->enable_flow; memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX + 1); err = prio_dump_offload(sch); Loading