Hi Alex,
On 10/12/2017 11:38 AM, Alexander Duyck wrote: > From: Alexander Duyck <alexander.h.du...@intel.com> > > This patch makes a slight tweak to mqprio in order to bring the > classid values used back in line with what is used for mq. The general idea > is to reserve values :ffe0 - :ffef to identify hardware traffic classes > normally reported via dev->num_tc. By doing this we can maintain a > consistent behavior with mq for classid where :1 - :ffdf will represent a > physical qdisc mapped onto a Tx queue represented by classid - 1, and the > traffic classes will be mapped onto a known subset of classid values > reserved for our virtual qdiscs. > > Note I reserved the range from :fff0 - :ffff since this way we might be > able to reuse these classid values with clsact and ingress which would mean > that for mq, mqprio, ingress, and clsact we should be able to maintain a > similar classid layout. > > Signed-off-by: Alexander Duyck <alexander.h.du...@intel.com> > --- > > So I thought I would put this out here as a first step towards trying to > address some of Jiri's concerns about wanting to have a consistent > userspace API. > > The plan is to follow this up with patches to ingress and clsact to look at > exposing a set of virtual qdiscs similar to what we already have for the HW > traffic classes in mqprio, although I won't bother with the ability to dump > class stats since they don't actually enqueue anything. > > include/uapi/linux/pkt_sched.h | 1 + > net/sched/sch_mqprio.c | 79 > +++++++++++++++++++++++----------------- > 2 files changed, 47 insertions(+), 33 deletions(-) > > diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h > index 099bf5528fed..174f1cf7e7f9 100644 > --- a/include/uapi/linux/pkt_sched.h > +++ b/include/uapi/linux/pkt_sched.h > @@ -74,6 +74,7 @@ struct tc_estimator { > #define TC_H_INGRESS (0xFFFFFFF1U) > #define TC_H_CLSACT TC_H_INGRESS > > +#define TC_H_MIN_PRIORITY 0xFFE0U > #define TC_H_MIN_INGRESS 0xFFF2U > #define TC_H_MIN_EGRESS 0xFFF3U > > diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c > index 6bcdfe6e7b63..a61ef119a556 100644 > --- a/net/sched/sch_mqprio.c > +++ b/net/sched/sch_mqprio.c > @@ -115,6 +115,10 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr > *opt) > if (!netif_is_multiqueue(dev)) > return -EOPNOTSUPP; > > + /* make certain can allocate enough classids to handle queues */ > + if (dev->num_tx_queues >= TC_H_MIN_PRIORITY) > + return -ENOMEM; > + > if (!opt || nla_len(opt) < sizeof(*qopt)) > return -EINVAL; > > @@ -193,7 +197,7 @@ static struct netdev_queue *mqprio_queue_get(struct Qdisc > *sch, > unsigned long cl) > { > struct net_device *dev = qdisc_dev(sch); > - unsigned long ntx = cl - 1 - netdev_get_num_tc(dev); > + unsigned long ntx = cl - 1; > > if (ntx >= dev->num_tx_queues) > return NULL; > @@ -282,38 +286,35 @@ static unsigned long mqprio_find(struct Qdisc *sch, u32 > classid) > struct net_device *dev = qdisc_dev(sch); > unsigned int ntx = TC_H_MIN(classid); > > - if (ntx > dev->num_tx_queues + netdev_get_num_tc(dev)) > - return 0; > - return ntx; > + /* There are essentially two regions here that have valid classid > + * values. The first region will have a classid value of 1 through > + * num_tx_queues. All of these are backed by actual Qdiscs. > + */ > + if (ntx < TC_H_MIN_PRIORITY) > + return (ntx <= dev->num_tx_queues) ? ntx : 0; > + > + /* The second region represents the hardware traffic classes. These > + * are represented by classid values of TC_H_MIN_PRIORITY through > + * TC_H_MIN_PRIORITY + netdev_get_num_tc - 1 > + */ > + return ((ntx - TC_H_MIN_PRIORITY) < netdev_get_num_tc(dev)) ? ntx : 0; > } > > static int mqprio_dump_class(struct Qdisc *sch, unsigned long cl, > struct sk_buff *skb, struct tcmsg *tcm) > { > - struct net_device *dev = qdisc_dev(sch); > + if (cl < TC_H_MIN_PRIORITY) { > + struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); > + struct net_device *dev = qdisc_dev(sch); > + int tc = netdev_txq_to_tc(dev, cl - 1); > > - if (cl <= netdev_get_num_tc(dev)) { > + tcm->tcm_parent = (tc < 0) ? 0 : > + TC_H_MAKE(TC_H_MAJ(sch->handle), > + TC_H_MIN(tc + TC_H_MIN_PRIORITY)); > + tcm->tcm_info = dev_queue->qdisc_sleeping->handle; > + } else { > tcm->tcm_parent = TC_H_ROOT; > tcm->tcm_info = 0; > - } else { > - int i; > - struct netdev_queue *dev_queue; > - > - dev_queue = mqprio_queue_get(sch, cl); > - tcm->tcm_parent = 0; > - for (i = 0; i < netdev_get_num_tc(dev); i++) { > - struct netdev_tc_txq tc = dev->tc_to_txq[i]; > - int q_idx = cl - netdev_get_num_tc(dev); > - > - if (q_idx > tc.offset && > - q_idx <= tc.offset + tc.count) { > - tcm->tcm_parent = > - TC_H_MAKE(TC_H_MAJ(sch->handle), > - TC_H_MIN(i + 1)); > - break; > - } > - } > - tcm->tcm_info = dev_queue->qdisc_sleeping->handle; > } > tcm->tcm_handle |= TC_H_MIN(cl); > return 0; > @@ -324,15 +325,14 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, > unsigned long cl, > __releases(d->lock) > __acquires(d->lock) > { > - struct net_device *dev = qdisc_dev(sch); > - > - if (cl <= netdev_get_num_tc(dev)) { > + if (cl >= TC_H_MIN_PRIORITY) { > int i; > __u32 qlen = 0; > struct Qdisc *qdisc; > struct gnet_stats_queue qstats = {0}; > struct gnet_stats_basic_packed bstats = {0}; > - struct netdev_tc_txq tc = dev->tc_to_txq[cl - 1]; > + struct net_device *dev = qdisc_dev(sch); > + struct netdev_tc_txq tc = dev->tc_to_txq[cl & TC_BITMASK]; > > /* Drop lock here it will be reclaimed before touching > * statistics this is required because the d->lock we > @@ -385,12 +385,25 @@ static void mqprio_walk(struct Qdisc *sch, struct > qdisc_walker *arg) > > /* Walk hierarchy with a virtual class per tc */ > arg->count = arg->skip; > - for (ntx = arg->skip; > - ntx < dev->num_tx_queues + netdev_get_num_tc(dev); > - ntx++) { > + for (ntx = arg->skip; ntx < netdev_get_num_tc(dev); ntx++) { > + if (arg->fn(sch, ntx + TC_H_MIN_PRIORITY, arg) < 0) { > + arg->stop = 1; > + return; > + } > + arg->count++; > + } > + > + /* Pad the values and skip over unused traffic classes */ > + if (ntx < TC_MAX_QUEUE) { > + arg->count = TC_MAX_QUEUE; > + ntx = TC_MAX_QUEUE; > + } > + > + /* Reset offset, sort out remaining per-queue qdiscs */ > + for (ntx -= TC_MAX_QUEUE; ntx < dev->num_tx_queues; ntx++) { > if (arg->fn(sch, ntx + 1, arg) < 0) { > arg->stop = 1; > - break; > + return; > } > arg->count++; > } > Tested-by: Jesus Sanchez-Palencia <jesus.sanchez-palen...@intel.com> Looks good. thanks, Jesus