net/sched: add skbprio scheduler
Subsystems (4)
PATCH v3 1/1 net/sched: add skbprio scheduler
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their skb->priority field. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.
v3
*Drop max_limit parameter in struct skbprio_sched_data and instead use sch->limit.
*Reference qdisc_dev(sch)->tx_queue_len only once, during initialisation for qdisc (previously being referenced every time qdisc changes).
*Move qdisc's detailed description from in-code to Documentation/networking.
*When qdisc is saturated, enqueue incoming packet first before dequeueing lowest priority packet in queue - improves usage of call stack registers.
*Introduce and use overlimit stat to keep track of number of dropped packets.
v2
*Use skb->priority field rather than DS field. Rename queueing discipline as SKB Priority Queue (previously Gatekeeper Priority Queue).
*Queueing discipline is made classful to expose Skbprio's internal priority queues.
--- Documentation/networking/sch_skbprio.txt | 24 +++ include/uapi/linux/pkt_sched.h | 15 ++ net/sched/Kconfig | 13 ++ net/sched/Makefile | 1 + net/sched/sch_skbprio.c | 330 +++++++++++++++++++++++++++++++ 5 files changed, 383 insertions(+) create mode 100644 Documentation/networking/sch_skbprio.txt create mode 100644 net/sched/sch_skbprio.c
Documentation/networking/sch_skbprio.txt new file +24 -0
@@ -0,0 +1,24 @@ +SKB Priority Queue +================== + +This qdisc schedules a packet according to skb->priority, where a higher +value places the packet closer to the exit of the queue. When the queue is +full, the lowest priority packet in the queue is dropped to make room for +the packet to be added if it has higher priority. If the packet to be added +has lower priority than all packets in the queue, it is dropped. + +Without the SKB priority queue, queue length limits must be imposed +for individual queues, and there is no easy way to enforce a global queue +length limit across all priorities. With the SKBprio queue, a global +queue length limit can be enforced while not restricting the queue lengths +of individual priorities. + +This is especially useful for a denial-of-service defense system like +Gatekeeper, which prioritizes packets in flows that demonstrate expected +behavior of legitimate users. The queue is flexible to allow any number +of packets of any priority up to the global limit of the scheduler +without risking resource overconsumption by a flood of low priority packets. + +The Gatekeeper codebase is found here: + + https://github.com/AltraMayor/gatekeeper
include/uapi/linux/pkt_sched.h +15 -0
@@ -124,6 +124,21 @@ struct tc_fifo_qopt {__u32 limit;/* Queue length: bytes for bfifo, packets for pfifo */ }; +/* SKBPRIO section */ + +/* +* Priorities go from zero to (SKBPRIO_MAX_PRIORITY - 1). +* SKBPRIO_MAX_PRIORITY should be at least 64 in order for skbprio to be able +* to map one to one the DS field of IPV4 and IPV6 headers. +* Memory allocation grows linearly with SKBPRIO_MAX_PRIORITY. +*/ + +#define SKBPRIO_MAX_PRIORITY 64 + +struct tc_skbprio_qopt { +__u32 limit;/* Queue length in packets. */ +}; +/* PRIO section */ #define TCQ_PRIO_BANDS 16
net/sched/Kconfig +13 -0
@@ -251,6 +251,19 @@ config NET_SCH_MQPRIO If unsure, say N. +config NET_SCH_SKBPRIO + tristate "SKB priority queue scheduler (SKBPRIO)" + help + Say Y here if you want to use the SKB priority queue + scheduler. This schedules packets according to skb->priority, + which is useful for request packets in DoS mitigation systems such + as Gatekeeper. + + To compile this driver as a module, choose M here: the module will + be called sch_skbprio. + + If unsure, say N. + config NET_SCH_CHOKE tristate "CHOose and Keep responsive flow scheduler (CHOKE)" help
net/sched/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o obj-$(CONFIG_NET_SCH_PLUG) += sch_plug.o obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o +obj-$(CONFIG_NET_SCH_SKBPRIO) += sch_skbprio.o obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o
net/sched/sch_skbprio.c new file +330 -0
330 lines not on this page · raw message
Signature · 1 line
1.9.1
Quoted 8 lines · Nishanth Devarajan
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their
skb->priorityfield. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.
Why can't we implement this as a new flag for sch_prio.c?
I don't see why this duplication is needed, especially because it will only be "slower" (as in, it will do more work) when qdisc is already full and dropping packets anyway.
Marcelo
Quoted 10 lines · Marcelo Ricardo Leitner
Quoted 8 lines · Nishanth Devarajan
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their
skb->priorityfield. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.
Quoted 5 lines
Why can't we implement this as a new flag for
sch_prio.c?I don't see why this duplication is needed, especially because it will only be "slower" (as in, it will do more work) when qdisc is already full and dropping packets anyway.
sch_prio.c and skbprio diverge on a number of aspects:
1. sch_prio.c supports up to 16 priorities whereas skbprio 64. This
is not just a matter of changing a constant since sch_prio.c doesn't use skb->priority.
2. sch_prio.c does not have a global limit on the number of packets
on all its queues, only a limit per queue.
3. The queues of sch_prio.c are struct Qdisc, which don't have a
method to drop at its tail.
Given the divergences, adding flags to sch_prio.c will essentially
keep both implementations together instead of being isolated as being proposed.
On the speed point, there may not be noticeable difference between
both qdiscs because the enqueueing and dequeueing costs of both qdics are O(1). Notice that the "extra work" (i.e. dropping lower priority packets) is a key aspect of skbprio since it gives routers a cheap way to choose which packets to drop during a DoS.
[ ]'s
Michel Machado
Quoted 17 lines · Michel Machado
Quoted 10 lines · Marcelo Ricardo Leitner
Quoted 8 lines · Nishanth Devarajan
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their
skb->priorityfield. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.Quoted 5 lines
Why can't we implement this as a new flag for
sch_prio.c?I don't see why this duplication is needed, especially because it will only be "slower" (as in, it will do more work) when qdisc is already full and dropping packets anyway.
Quoted 5 lines
sch_prio.cand skbprio diverge on a number of aspects:1.
sch_prio.csupports up to 16 priorities whereas skbprio 64. This is
not just a matter of changing a constant sincesch_prio.cdoesn't useskb->priority.
Yes it does use skb->priority for classifying into a band:
prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
{
struct prio_sched_data *q = qdisc_priv(sch);
u32 band = skb->priority;...
Quoted 3 lines
2.
sch_prio.cdoes not have a global limit on the number of packets on
all its queues, only a limit per queue.
It can be useful to sch_prio.c as well, why not?prio_enqueue()
{
...
+ if (count > sch->global_limit)
+ prio_tail_drop(sch); /* to be implemented */
ret = qdisc_enqueue(skb, qdisc, to_free);
Quoted 3 lines
3. The queues of
sch_prio.care struct Qdisc, which don't have a method
to drop at its tail.
That can be implemented, most likely as prio_tail_drop() as above.
Quoted 3 lines
Given the divergences, adding flags to
sch_prio.cwill essentially keep
both implementations together instead of being isolated as being proposed.
I don't agree. There aren't that many flags. I see only 2, one which makes sense to sch_prio as it is already (the global limit) and from where it should drop, the overflown packet or from tail.
All other code will be reused: stats handling, netlink handling, enqueue and dequeue at least.
If we add this other qdisc, named as it is, it will be very confusing to sysadmins: both are named very closely and work essentially in the same way, but one drops from tail and another drops the incoming packet.
Quoted 6 lines
On the speed point, there may not be noticeable difference between both
qdiscs because the enqueueing and dequeueing costs of both qdics are O(1). Notice that the "extra work" (i.e. dropping lower priority packets) is a key aspect of skbprio since it gives routers a cheap way to choose which packets to drop during a DoS.
On that I agree. I was more referring to something like: "lets not make sch_prio slow and implement a new one instead.", which I don't it's valid because the extra "cost" is only visible when it's already dropping packets. Hopefully it's clearer now :)
[]s
Marcelo
Quoted 24 lines · Marcelo Ricardo Leitner
Quoted 17 lines · Michel Machado
Quoted 10 lines · Marcelo Ricardo Leitner
Quoted 8 lines · Nishanth Devarajan
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their
skb->priorityfield. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.Quoted 5 lines
Why can't we implement this as a new flag for
sch_prio.c?I don't see why this duplication is needed, especially because it will only be "slower" (as in, it will do more work) when qdisc is already full and dropping packets anyway.
Quoted 5 lines
sch_prio.cand skbprio diverge on a number of aspects:1.
sch_prio.csupports up to 16 priorities whereas skbprio 64. This is
not just a matter of changing a constant sincesch_prio.cdoesn't useskb->priority.
Quoted 7 lines
Yes it does use
skb->priorityfor classifying into a band:
prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr){ struct prio_sched_data *q = qdisc_priv(sch); u32 band = skb->priority;...
Changing TC_PRIO_MAX from 15 to 63 risks breaking backward
compatibility with applications.
Quoted 4 lines
Quoted 2 lines
3. The queues of
sch_prio.care struct Qdisc, which don't have a method
to drop at its tail.That can be implemented, most likely as
prio_tail_drop()as above.
struct Qdisc represents *all* qdiscs. My knowledge of the other
qdiscs is limited, but not all qdiscs may have a meaningful method to drop at the tail. For example: a qdisc that works over flows may not know with flow is the tail. Not to mention that this would be a widespread patch to only support this new prio qdisc. It would be prudent to wait for the production success of the proposed, self-contained qdisc before making this commitment.
[ ]'s
Michel Machado
Quoted 27 lines · Michel Machado
Quoted 26 lines · Marcelo Ricardo Leitner
Quoted 17 lines · Michel Machado
Quoted 10 lines · Marcelo Ricardo Leitner
Quoted 8 lines · Nishanth Devarajan
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their
skb->priorityfield. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.Quoted 5 lines
Why can't we implement this as a new flag for
sch_prio.c?I don't see why this duplication is needed, especially because it will only be "slower" (as in, it will do more work) when qdisc is already full and dropping packets anyway.
Quoted 5 lines
sch_prio.cand skbprio diverge on a number of aspects:1.
sch_prio.csupports up to 16 priorities whereas skbprio 64. This is
not just a matter of changing a constant sincesch_prio.cdoesn't useskb->priority.Yes it does use
skb->priorityfor classifying into a band:
Quoted 8 lines
Quoted 5 lines
prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr){ struct prio_sched_data *q = qdisc_priv(sch); u32 band = skb->priority;...
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.
If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
You can get 64 different priorities by stacking sch_prio, btw. And if you implement drop_from_tail() as part of Qdisc, you can even get it working for this cascading case too.
Quoted 9 lines
Quoted 5 lines
Quoted 3 lines
3. The queues of
sch_prio.care struct Qdisc, which don't have a method
to drop at its tail.That can be implemented, most likely as
prio_tail_drop()as above.struct Qdisc represents *all* qdiscs. My knowledge of the other qdiscs is
limited, but not all qdiscs may have a meaningful method to drop at the tail. For example: a qdisc that works over flows may not know with flow is
True, but it doesn't mean you have to implement it for all available qdiscs.
Quoted 3 lines
the tail. Not to mention that this would be a widespread patch to only support this new prio qdisc. It would be prudent to wait for the production success of the proposed, self-contained qdisc before making this commitment.
On the other hand, by adding another qdisc you're adding more work that one needs to do when dealing with qdisc infrastructure, such as updating enqueue() prototype, for example.
Once this new qdisc is in, it won't be easy to deprecate it.
Marcelo
Quoted 37 lines · Marcelo Ricardo Leitner
Quoted 27 lines · Michel Machado
Quoted 26 lines · Marcelo Ricardo Leitner
Quoted 17 lines · Michel Machado
Quoted 10 lines · Marcelo Ricardo Leitner
Quoted 8 lines · Nishanth Devarajan
net/sched: add skbprio scheduer
Skbprio (SKB Priority Queue) is a queueing discipline that prioritizes packets according to their
skb->priorityfield. Under congestion, already-enqueued lower priority packets will be dropped to make space available for higher priority packets. Skbprio was conceived as a solution for denial-of-service defenses that need to route packets with different priorities as a means to overcome DoS attacks.Quoted 5 lines
Why can't we implement this as a new flag for
sch_prio.c?I don't see why this duplication is needed, especially because it will only be "slower" (as in, it will do more work) when qdisc is already full and dropping packets anyway.
Quoted 5 lines
sch_prio.cand skbprio diverge on a number of aspects:1.
sch_prio.csupports up to 16 priorities whereas skbprio 64. This is
not just a matter of changing a constant sincesch_prio.cdoesn't useskb->priority.Yes it does use
skb->priorityfor classifying into a band:Quoted 8 lines
Quoted 5 lines
prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr){ struct prio_sched_data *q = qdisc_priv(sch); u32 band = skb->priority;...
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.
Quoted 7 lines
If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
You can get 64 different priorities by stacking
sch_prio, btw. And if you implementdrop_from_tail()as part of Qdisc, you can even get it working for this cascading case too.
A solution would be to add another flag to switch between the
current prio_classify() and a new one to just use skb->priority as in skbprio. This way we don't risk breaking applications that rely on tcf_classify() and this odd behavior that I found in prio_classify():
band = TC_H_MIN(band) - 1;
if (band >= q->bands)
return q->queues[q->prio2band[0]];
return q->queues[band]; When band is zero, it returns q->queues[q->prio2band[0]] instead of
q->queues[band] as it would for other bands less than q->bands.
Quoted 10 lines
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
3. The queues of
sch_prio.care struct Qdisc, which don't have a method
to drop at its tail.That can be implemented, most likely as
prio_tail_drop()as above.struct Qdisc represents *all* qdiscs. My knowledge of the other qdiscs is
limited, but not all qdiscs may have a meaningful method to drop at the tail. For example: a qdisc that works over flows may not know with flow isTrue, but it doesn't mean you have to implement it for all available qdiscs.
If it is not implemented for all available qdiscs and the flag to
drop at the tail is on, sch_prio.c would need to issue a log message whenever a packet goes into one of the subqueues that don't drop at the tail and have a failsafe behavior.
Quoted 9 lines
Quoted 3 lines
the tail. Not to mention that this would be a widespread patch to only support this new prio qdisc. It would be prudent to wait for the production success of the proposed, self-contained qdisc before making this commitment.
On the other hand, by adding another qdisc you're adding more work that one needs to do when dealing with qdisc infrastructure, such as updating
enqueue()prototype, for example.Once this new qdisc is in, it won't be easy to deprecate it.
We need to choose between (1) having skbprio that has some duplicate
code with sch_prio.c and (2) adding flags to sch_prio.c and make a major refactoring of the schedule subsystem to add drop an the tail to qdiscs.
I mean major because we are not just talking about adding the methoddequeue_tail() to struct Qdisc and adding dequeue_tail() to all qdiscs. One will need to come up with definitions of dequeue_tail() for qdiscs that don't naturally have it and even rewrite the data structures of qdiscs. To substantiate this last point, consider sch_fifo.c, one of the simplest qdiscs available. sch_fifo.c keeps its packets in sch->q, which is of type struct qdisc_skb_head. struct qdisc_skb_head doesn't set skb->prev, so it cannot drop at the tail without walking through its list.
I do understand the motivation for minimizing duplicate code. But
the small amount of duplicate code that skbprio adds is cheaper than refactoring the scheduler system to only support this new sch_prio.c.
[ ]'s
Michel Machado
On Tue, Jul 10, 2018 at 10:03:22AM -0400, Michel Machado wrote:
...
Quoted 6 lines
Quoted 3 lines
You can get 64 different priorities by stacking
sch_prio, btw. And if you implementdrop_from_tail()as part of Qdisc, you can even get it working for this cascading case too.A solution would be to add another flag to switch between the current
prio_classify()and a new one to just useskb->priorityas in skbprio. This
Sounds promising.
Quoted 10 lines
way we don't risk breaking applications that rely on
tcf_classify()and this odd behavior that I found inprio_classify():band = TC_H_MIN(band) - 1; if (band >= q->bands) return q->queues[q->prio2band[0]]; return q->queues[band];When band is zero, it returns q->queues[q->prio2band[0]] instead of
q->queues[band] as it would for other bands less thanq->bands.
Agreed, this looks odd. It came from 1d8ae3fdeb00 ("pkt_sched: Remove RR scheduler."):
band = TC_H_MIN(band) - 1;
if (band >= q->bands)- band = q->prio2band[0];
-out:
- if (q->mq)
- skb_set_queue_mapping(skb, band);
+ return q->queues[q->prio2band[0]];
+
return q->queues[band];
}
I can see how it made sense before the change, but not after.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 5 lines
Quoted 3 lines
3. The queues of
sch_prio.care struct Qdisc, which don't have a method
to drop at its tail.That can be implemented, most likely as
prio_tail_drop()as above.struct Qdisc represents *all* qdiscs. My knowledge of the other qdiscs is
limited, but not all qdiscs may have a meaningful method to drop at the tail. For example: a qdisc that works over flows may not know with flow is
Quoted 6 lines
Quoted 1 line
True, but it doesn't mean you have to implement it for all available qdiscs.
If it is not implemented for all available qdiscs and the flag to drop at
the tail is on,sch_prio.cwould need to issue a log message whenever a packet goes into one of the subqueues that don't drop at the tail and have a failsafe behavior.
That's fine. pr_warn_ratelimit() is probably what we need for logging the error, so it a) doesn't flood kernel log and b) gets activated even if the sysadmin later try again with another qdisc (as opposed to pr_warn_once).
For the failsafe behavior, it probably can then just drop the incoming packet. It is not what you want, yes, but it's an easy way out out of a non-expected situation and that works well enough.
Quoted 9 lines
Quoted 9 lines
Quoted 4 lines
the tail. Not to mention that this would be a widespread patch to only support this new prio qdisc. It would be prudent to wait for the production success of the proposed, self-contained qdisc before making this commitment.
On the other hand, by adding another qdisc you're adding more work that one needs to do when dealing with qdisc infrastructure, such as updating
enqueue()prototype, for example.
Quoted 5 lines
Quoted 1 line
Once this new qdisc is in, it won't be easy to deprecate it.
We need to choose between (1) having skbprio that has some duplicate code
withsch_prio.cand (2) adding flags tosch_prio.cand make a major refactoring of the schedule subsystem to add drop an the tail to qdiscs.
Yes,
Quoted 3 lines
I mean major because we are not just talking about adding the method
dequeue_tail()to struct Qdisc and addingdequeue_tail()to all qdiscs. One
I think it is. :-)
Quoted 6 lines
will need to come up with definitions of
dequeue_tail()for qdiscs that don't naturally have it and even rewrite the data structures of qdiscs. To substantiate this last point, considersch_fifo.c, one of the simplest qdiscs available.sch_fifo.ckeeps its packets insch->q, which is of type structqdisc_skb_head. structqdisc_skb_headdoesn't setskb->prev, so it cannot drop at the tail without walking through its list.
Yes but this would only be needed for the qdiscs that you want to support with this flag. Nobody said you need to implement it on all qdiscs that we have...
Quoted 4 lines
I do understand the motivation for minimizing duplicate code. But the
small amount of duplicate code that skbprio adds is cheaper than refactoring the scheduler system to only support this newsch_prio.c.
I'm afraid that without the code for option (2) above, this discussion will become subjective. I'll wait for other opinions here.
Cheers,
Marcelo
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
struct tc_prio_qopt {
int bands; /* Number of bands */
__u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};
How would you do it carefully?
Also, it is not only used by prio but also pfifo_fast.
Quoted 11 lines · Cong Wang
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
Quoted 6 lines
struct
tc_prio_qopt{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};How would you do it carefully?
quick shot, multiplex v1 and v2 formats based on bands and sizeof():
#define TCQ_PRIO_BANDS_V1 16
#define TCQ_PRIO_BANDS_V2 64
#define TC_PRIO_MAX_V2 64
struct tc_prio_qopt_v2 {
int bands; /* Number of bands */
__u8 priomap[TC_PRIO_MAX_V2+1]; /* Map: logical priority -> PRIO band */
};
static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
struct prio_sched_data *q = qdisc_priv(sch);
struct Qdisc *queues[TCQ_PRIO_BANDS_V2];
int oldbands = q->bands, i;
struct tc_prio_qopt_v2 *qopt;
if (nla_len(opt) < sizeof(int))
return -EINVAL;
qopt = nla_data(opt);
if (qopt->bands <= TCQ_PRIO_BANDS_V1 &&
nla_len(opt) < sizeof(struct tc_prio_qopt))
return -EINVAL;
if (qopt->bands <= TCQ_PRIO_BANDS_V2 &&
nla_len(opt) < sizeof(*qopt))
return -EINVAL;
/* By here, if it has up to 3 bands, we can assume it is using the _v1
* layout, while if it has up to TCQ_PRIO_BANDS_V2 it is using the _v2
* format.
*/
if (qopt->bands > TCQ_PRIO_BANDS_V2 || qopt->bands < 2)
return -EINVAL;...
With something like this I think it can keep compatibility with old software while also allowing the new usage.
Quoted 1 line
Also, it is not only used by prio but also
pfifo_fast.
Yes. More is needed, indeed. prio2band would also need to be expanded, etc. Yet, I still don't see any blocker.
Quoted 22 lines · Marcelo Ricardo Leitner
Quoted 11 lines · Cong Wang
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
Quoted 6 lines
struct
tc_prio_qopt{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};How would you do it carefully?
quick shot, multiplex v1 and v2 formats based on bands and
sizeof():
Quoted 9 lines
#define TCQ_PRIO_BANDS_V1 16 #define TCQ_PRIO_BANDS_V2 64 #define TC_PRIO_MAX_V2 64struct
tc_prio_qopt_v2{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX_V2+1]; /* Map: logical priority -> PRIO band */
};
Good try, but:
1. You don't take padding into account, although the difference between 16 and 64 is big here. If it were 16 and 20, almost certainly wouldn't work.
2. What if I compile a new iproute2 on an old kernel? The iproute2 will use V2, while old kernel has no knowledge of V2, so it only copies a part of V2 in the end....
Quoted 34 lines · Cong Wang
Quoted 22 lines · Marcelo Ricardo Leitner
Quoted 11 lines · Cong Wang
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
Quoted 6 lines
struct
tc_prio_qopt{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};How would you do it carefully?
quick shot, multiplex v1 and v2 formats based on bands and
sizeof():Quoted 9 lines
#define TCQ_PRIO_BANDS_V1 16 #define TCQ_PRIO_BANDS_V2 64 #define TC_PRIO_MAX_V2 64struct
tc_prio_qopt_v2{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX_V2+1]; /* Map: logical priority -> PRIO band */
};
Quoted 5 lines
Good try, but:
1. You don't take padding into account, although the difference between 16 and 64 is big here. If it were 16 and 20, almost certainly wouldn't work.
It still would work, no matter how much padding you have, as currently you can't use more than 3 bands.
Quoted 4 lines
2. What if I compile a new iproute2 on an old kernel? The iproute2 will use V2, while old kernel has no knowledge of V2, so it only copies a part of V2 in the end....
Yes, and that's not a problem:
- Either bands is > 3 and it will return EINVAL, protecting from reading beyond the buffer.
- Or 2 <= bands <= 3 and it will handle it as a _v1 struct, and use only the original size.
iproute2 (or other app) may still use _v1 if it wants, btw.
Quoted 36 lines · Marcelo Ricardo Leitner
Quoted 34 lines · Cong Wang
Quoted 31 lines · Marcelo Ricardo Leitner
Quoted 11 lines · Cong Wang
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
Quoted 6 lines
struct
tc_prio_qopt{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};How would you do it carefully?
quick shot, multiplex v1 and v2 formats based on bands and
sizeof():#define TCQ_PRIO_BANDS_V1 16 #define TCQ_PRIO_BANDS_V2 64 #define TC_PRIO_MAX_V2 64struct
tc_prio_qopt_v2{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX_V2+1]; /* Map: logical priority -> PRIO band */
};
Quoted 8 lines
Quoted 5 lines
Good try, but:
1. You don't take padding into account, although the difference between 16 and 64 is big here. If it were 16 and 20, almost certainly wouldn't work.
It still would work, no matter how much padding you have, as currently you can't use more than 3 bands.
I am lost.
With your proposal above, you have 16 bands for V1 and 64 bands for V2, where does 3 come from???
Quoted 11 lines
Quoted 5 lines
2. What if I compile a new iproute2 on an old kernel? The iproute2 will use V2, while old kernel has no knowledge of V2, so it only copies a part of V2 in the end....
Yes, and that's not a problem:
- Either bands is > 3 and it will return EINVAL, protecting from reading beyond the buffer.
- Or 2 <= bands <= 3 and it will handle it as a_v1struct, and use only the original size.
Again why 3 not 16 or 64 ??
Also, why does an old kernel has the logic in its binary to determine this?
Quoted 2 lines
iproute2 (or other app) may still use
_v1if it wants, btw.
Yes, old iproute2 must still have v1, what's point? Are you suggesting new iproute2 should still have v1 after you propose v1 and v2 for kernel?
I must seriously miss something. Please help.
Thanks!
Quoted 44 lines · Cong Wang
Quoted 42 lines · Marcelo Ricardo Leitner
Quoted 39 lines · Cong Wang
Quoted 22 lines · Marcelo Ricardo Leitner
Quoted 11 lines · Cong Wang
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
Quoted 6 lines
struct
tc_prio_qopt{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};How would you do it carefully?
quick shot, multiplex v1 and v2 formats based on bands and
sizeof():Quoted 9 lines
#define TCQ_PRIO_BANDS_V1 16 #define TCQ_PRIO_BANDS_V2 64 #define TC_PRIO_MAX_V2 64struct
tc_prio_qopt_v2{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX_V2+1]; /* Map: logical priority -> PRIO band */
};Good try, but:
1. You don't take padding into account, although the difference between 16 and 64 is big here. If it were 16 and 20, almost certainly wouldn't work.
Quoted 7 lines
Quoted 2 lines
It still would work, no matter how much padding you have, as currently you can't use more than 3 bands.
I am lost.
With your proposal above, you have 16 bands for V1 and 64 bands for V2, where does 3 come from???
My bad. s/3/16/
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
2. What if I compile a new iproute2 on an old kernel? The iproute2 will use V2, while old kernel has no knowledge of V2, so it only copies a part of V2 in the end....
Quoted 7 lines
Quoted 5 lines
Yes, and that's not a problem:
- Either bands is > 3 and it will return EINVAL, protecting from reading beyond the buffer.
- Or 2 <= bands <= 3 and it will handle it as a_v1struct, and use only the original size.Again why 3 not 16 or 64 ??
Again, s/3/16/
Quoted 3 lines
Also, why does an old kernel has the logic in its binary to determine this?
It won't, and it doesn't need to. If you use bands > 16 with an old kernel, it will reject per current code (that I already pasted):
if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2)
return -EINVAL;Simple as that. If you try to use more bands than it supports, it will reject it.
Quoted 5 lines
Quoted 3 lines
iproute2 (or other app) may still use
_v1if it wants, btw.Yes, old iproute2 must still have v1, what's point? Are you
??
Quoted 2 lines
suggesting new iproute2 should still have v1 after you propose v1 and v2 for kernel?
I'm only saying that both versions will be accepted by a new kernel.
Quoted 4 lines
I must seriously miss something. Please help.
Thanks!
Quoted 49 lines · Marcelo Ricardo Leitner
Quoted 47 lines · Cong Wang
Quoted 44 lines · Marcelo Ricardo Leitner
Quoted 34 lines · Cong Wang
Quoted 22 lines · Marcelo Ricardo Leitner
Quoted 11 lines · Cong Wang
Quoted 8 lines · Marcelo Ricardo Leitner
Quoted 2 lines · Michel Machado
Changing
TC_PRIO_MAXfrom 15 to 63 risks breaking backward compatibility
with applications.If done, it needs to be done carefully, indeed. I don't know if it's doable, neither I know how hard is your requirement for 64 different priorities.
Quoted 6 lines
struct
tc_prio_qopt{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};How would you do it carefully?
quick shot, multiplex v1 and v2 formats based on bands and
sizeof():Quoted 9 lines
#define TCQ_PRIO_BANDS_V1 16 #define TCQ_PRIO_BANDS_V2 64 #define TC_PRIO_MAX_V2 64struct
tc_prio_qopt_v2{
int bands; /* Number of bands */
__u8priomap[TC_PRIO_MAX_V2+1]; /* Map: logical priority -> PRIO band */
};Quoted 5 lines
Good try, but:
1. You don't take padding into account, although the difference between 16 and 64 is big here. If it were 16 and 20, almost certainly wouldn't work.
It still would work, no matter how much padding you have, as currently you can't use more than 3 bands.
Quoted 6 lines
Quoted 4 lines
I am lost.
With your proposal above, you have 16 bands for V1 and 64 bands for V2, where does 3 come from???
My bad. s/3/16/
Ah, thanks for clarifying it! Please see below.
Quoted 23 lines
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
2. What if I compile a new iproute2 on an old kernel? The iproute2 will use V2, while old kernel has no knowledge of V2, so it only copies a part of V2 in the end....
Quoted 7 lines
Quoted 5 lines
Yes, and that's not a problem:
- Either bands is > 3 and it will return EINVAL, protecting from reading beyond the buffer.
- Or 2 <= bands <= 3 and it will handle it as a_v1struct, and use only the original size.Again why 3 not 16 or 64 ??
Again, s/3/16/
Quoted 3 lines
Also, why does an old kernel has the logic in its binary to determine this?
Quoted 8 lines
It won't, and it doesn't need to. If you use bands > 16 with an old kernel, it will reject per current code (that I already pasted):
if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2) return -EINVAL;Simple as that. If you try to use more bands than it supports, it will reject it.
Hmm, I see, But in your demo code, you miss the following pieces:
for (i = 0; i <= TC_PRIO_MAX; i++) {
if (qopt->priomap[i] >= qopt->bands)
return -EINVAL;
}
memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);I guess you want to change TC_PRIO_MAX to qopt->bands too.
With this together, your suggestion actually looks reasonable.
Do I understand it correctly?
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
iproute2 (or other app) may still use
_v1if it wants, btw.
Quoted 8 lines
Quoted 1 line
Yes, old iproute2 must still have v1, what's point? Are you
??
Quoted 2 lines
suggesting new iproute2 should still have v1 after you propose v1 and v2 for kernel?
I'm only saying that both versions will be accepted by a new kernel.
I see, I thought you suggest to completely move to V2 for new kernel.
Nice compatibility trick!
Thanks.
Quoted 11 lines · Marcelo Ricardo Leitner
Quoted 3 lines · Michel Machado
2.
sch_prio.cdoes not have a global limit on the number of packets on
all its queues, only a limit per queue.It can be useful to
sch_prio.cas well, why not?prio_enqueue()
{
...
Review
Quoted 3 lines
(quoted diff) +2
-0+ if (count > sch->global_limit) + prio_tail_drop(sch); /* to be implemented */ ret = qdisc_enqueue(skb, qdisc, to_free);
Isn't the whole point of sch_prio offloading the queueing to each class? If you need a limit, there is one for each child qdisc if you use for example pfifo or bfifo (depending on you want to limit bytes or packets).
Also, what's your plan for backward compatibility here?
Quoted 17 lines · Cong Wang
Quoted 11 lines · Marcelo Ricardo Leitner
Quoted 3 lines · Michel Machado
2.
sch_prio.cdoes not have a global limit on the number of packets on
all its queues, only a limit per queue.It can be useful to
sch_prio.cas well, why not?prio_enqueue()
{
...Review
Quoted 3 lines
(quoted diff) +2
-0+ if (count > sch->global_limit) + prio_tail_drop(sch); /* to be implemented */ ret = qdisc_enqueue(skb, qdisc, to_free);
Quoted 4 lines
Isn't the whole point of
sch_priooffloading the queueing to each class? If you need a limit, there is one for each child qdisc if you use for example pfifo or bfifo (depending on you want to limit bytes or packets).
Yes, but Michel wants to drop from other lower priorities if needed, and that's not possible if you handle the limit already in a child qdisc as they don't know about their siblings. The idea in the example above is to discard it from whatever lower priority is needed, then queue it. (ok, the example missed to check the priority level)
As for the different units, sch_prio holds a count of how many packets are queued on its children, and that's what would be used for the limit.
Quoted 2 lines
Also, what's your plan for backward compatibility here?
say:
if (sch->global_limit && count > sch->global_limit)
as in, only do the limit check/enforcing if needed.
Quoted 24 lines · Marcelo Ricardo Leitner
Quoted 17 lines · Cong Wang
Quoted 11 lines · Marcelo Ricardo Leitner
Quoted 3 lines · Michel Machado
2.
sch_prio.cdoes not have a global limit on the number of packets on
all its queues, only a limit per queue.It can be useful to
sch_prio.cas well, why not?prio_enqueue()
{
...Review
Quoted 3 lines
(quoted diff) +2
-0+ if (count > sch->global_limit) + prio_tail_drop(sch); /* to be implemented */ ret = qdisc_enqueue(skb, qdisc, to_free);Quoted 4 lines
Isn't the whole point of
sch_priooffloading the queueing to each class? If you need a limit, there is one for each child qdisc if you use for example pfifo or bfifo (depending on you want to limit bytes or packets).
Quoted 5 lines
Yes, but Michel wants to drop from other lower priorities if needed, and that's not possible if you handle the limit already in a child qdisc as they don't know about their siblings. The idea in the example above is to discard it from whatever lower priority is needed, then queue it. (ok, the example missed to check the priority level)
So it disproves your point of adding a flag to sch_prio, right?
Also, you have to re-introduce qdisc->ops->drop() if you really want to go this direction.
Quoted 10 lines
As for the different units,
sch_prioholds a count of how many packets are queued on its children, and that's what would be used for the limit.Quoted 2 lines
Also, what's your plan for backward compatibility here?
say:
if (sch->global_limit&& count >sch->global_limit)
as in, only do the limit check/enforcing if needed.
Obviously doesn't work, users could pass 0 to effectively disable the qdisc from enqueue'ing any packet.
Quoted 26 lines · Cong Wang
Quoted 24 lines · Marcelo Ricardo Leitner
Quoted 21 lines · Cong Wang
Quoted 11 lines · Marcelo Ricardo Leitner
Quoted 3 lines · Michel Machado
2.
sch_prio.cdoes not have a global limit on the number of packets on
all its queues, only a limit per queue.It can be useful to
sch_prio.cas well, why not?prio_enqueue()
{
...Review
Quoted 3 lines
(quoted diff) +2
-0+ if (count > sch->global_limit) + prio_tail_drop(sch); /* to be implemented */ ret = qdisc_enqueue(skb, qdisc, to_free);Isn't the whole point of
sch_priooffloading the queueing to each class? If you need a limit, there is one for each child qdisc if you use for example pfifo or bfifo (depending on you want to limit bytes or packets).
Quoted 7 lines
Quoted 5 lines
Yes, but Michel wants to drop from other lower priorities if needed, and that's not possible if you handle the limit already in a child qdisc as they don't know about their siblings. The idea in the example above is to discard it from whatever lower priority is needed, then queue it. (ok, the example missed to check the priority level)
So it disproves your point of adding a flag to
sch_prio, right?
I don't see how?
Quoted 3 lines
Also, you have to re-introduce
qdisc->ops->drop()if you really want to go this direction.
Again, yes. What's the deal with it?
Quoted 6 lines
Quoted 6 lines
As for the different units,
sch_prioholds a count of how many packets are queued on its children, and that's what would be used for the limit.Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Also, what's your plan for backward compatibility here?
say:
if (sch->global_limit&& count >sch->global_limit)
as in, only do the limit check/enforcing if needed.Obviously doesn't work, users could pass 0 to effectively disable the qdisc from enqueue'ing any packet.
If you only had considered the right 'limit' variable, you would be right here.
Quoted 34 lines · Marcelo Ricardo Leitner
Quoted 32 lines · Cong Wang
Quoted 29 lines · Marcelo Ricardo Leitner
Quoted 17 lines · Cong Wang
Quoted 11 lines · Marcelo Ricardo Leitner
Quoted 3 lines · Michel Machado
2.
sch_prio.cdoes not have a global limit on the number of packets on
all its queues, only a limit per queue.It can be useful to
sch_prio.cas well, why not?prio_enqueue()
{
...Review
Quoted 3 lines
(quoted diff) +2
-0+ if (count > sch->global_limit) + prio_tail_drop(sch); /* to be implemented */ ret = qdisc_enqueue(skb, qdisc, to_free);Quoted 4 lines
Isn't the whole point of
sch_priooffloading the queueing to each class? If you need a limit, there is one for each child qdisc if you use for example pfifo or bfifo (depending on you want to limit bytes or packets).Yes, but Michel wants to drop from other lower priorities if needed, and that's not possible if you handle the limit already in a child qdisc as they don't know about their siblings. The idea in the example above is to discard it from whatever lower priority is needed, then queue it. (ok, the example missed to check the priority level)
Quoted 3 lines
Quoted 1 line
So it disproves your point of adding a flag to
sch_prio, right?I don't see how?
Interesting, you said "Michel wants to drop from other lower priorities if needed", but sch_prio has no knowledge of this, you confirmed with "...if you handle the limit already in a child qdisc as they don't know about their siblings."
The if clause is true as the limit is indeed handled by its child qdiscs as designed.
Therefore, a simple of adding a flag to sch_prio, as you suggested and demonstrated above, doesn't work, as confirmed by your own words.
What am I missing here?
Are you go further by suggesting moving the limit out of prio? Or are you going to expand your definition of "adding a flag"? Perhaps two flags? :)
I am very open for discussion to see how far we can go.
Quoted 7 lines
Quoted 4 lines
Also, you have to re-introduce
qdisc->ops->drop()if you really want to go this direction.Again, yes. What's the deal with it?
Nothing, just want to tell you ops->drop() is nothing new, to help your discussion.
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
As for the different units,
sch_prioholds a count of how many packets are queued on its children, and that's what would be used for the limit.Quoted 2 lines
Also, what's your plan for backward compatibility here?
say:
if (sch->global_limit&& count >sch->global_limit)
as in, only do the limit check/enforcing if needed.
Quoted 5 lines
Quoted 2 lines
Obviously doesn't work, users could pass 0 to effectively disable the qdisc from enqueue'ing any packet.
If you only had considered the right 'limit' variable, you would be right here.
Yeah, that is exactly what you propose, isn't it? :)
Thanks!
On Fri, Jul 13, 2018 at 11:17:18AM -0700, Cong Wang wrote:
...
Quoted 20 lines
Quoted 11 lines
Quoted 11 lines
Quoted 10 lines
Quoted 4 lines
Isn't the whole point of
sch_priooffloading the queueing to each class? If you need a limit, there is one for each child qdisc if you use for example pfifo or bfifo (depending on you want to limit bytes or packets).Yes, but Michel wants to drop from other lower priorities if needed, and that's not possible if you handle the limit already in a child qdisc as they don't know about their siblings. The idea in the example above is to discard it from whatever lower priority is needed, then queue it. (ok, the example missed to check the priority level)
Quoted 3 lines
Quoted 1 line
So it disproves your point of adding a flag to
sch_prio, right?I don't see how?
Interesting, you said "Michel wants to drop from other lower priorities if needed", but
sch_priohas no knowledge of this, you confirmed with "...if you handle the limit already in a child qdisc as they don't know about their siblings."
Quoted 6 lines
The if clause is true as the limit is indeed handled by its child qdiscs as designed.
Therefore, a simple of adding a flag to
sch_prio, as you suggested and demonstrated above, doesn't work, as confirmed by your own words.
Well, it would help if you didn't cut out key parts of my words.
Quoted 8 lines
What am I missing here?
Are you go further by suggesting moving the limit out of prio? Or are you going to expand your definition of "adding a flag"? Perhaps two flags? :)
I am very open for discussion to see how far we can go.
I am not keen on continuing this discussion if you keep twisting my words just for fun.
Quoted 2 lines · Marcelo Ricardo Leitner
Well, it would help if you didn't cut out key parts of my words.
Sorry about it, please allow me to copy and paste all of your words here:
"Yes, but Michel wants to drop from other lower priorities if needed, and that's not possible if you handle the limit already in a child qdisc as they don't know about their siblings. The idea in the example above is to discard it from whatever lower priority is needed, then queue it. (ok, the example missed to check the priority level)"
So from your own words, you agreed "the idea in the example" is not what Michel wants, because "is to discard it from whatever lower priority is needed", as "Michel wants to drop from other lower priorities if needed".
You also agreed Michel's requirement is not possible (to implement in sch_prio) because "you handle the limit already in a child qdisc as they don't know about their siblings" is also true.
Based on the above, I said it "disproves your point of adding a flag to sch_prio".
What am I missing?
Quoted 4 lines
Quoted 4 lines
What am I missing here?
Quoted 8 lines
Quoted 5 lines
Are you go further by suggesting moving the limit out of prio? Or are you going to expand your definition of "adding a flag"? Perhaps two flags? :)
I am very open for discussion to see how far we can go.
I am not keen on continuing this discussion if you keep twisting my words just for fun.
No, I am trying to understand seriously about what you suggest here.
Please be patient! I know I am stupid!!!! :)
Thanks!
Quoted 2 lines · Michel Machado
3. The queues of
sch_prio.care struct Qdisc, which don't have a
method to drop at its tail.
This isn't true, you can install a qdisc which drops at tail as its child qdisc, you can install different qdiscs for different children too if you really want. The control is on you, sch_prio is simply a wrapper.
Documentation/networking/sch_skbprio.txt
Quoted 5 lines · Nishanth Devarajan
Documentation/networking/sch_skbprio.txt new file +0
-0
We usually document each qdisc behavior in tc man pages in iproute2.
I don't mind you document it in kernel, but it kinda breaks the tradition.
Documentation/networking/sch_skbprio.txt
Quoted 13 lines
Documentation/networking/sch_skbprio.txt new file +13
-0+static int skbprio_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +{ + struct skbprio_sched_data *q = qdisc_priv(sch); + struct tc_skbprio_qopt *ctl = nla_data(opt); + const unsigned int min_limit = 1; + + if (ctl->limit == (typeof(ctl->limit))-1) + sch->limit = max(qdisc_dev(sch)->tx_queue_len, min_limit); + else if (ctl->limit < min_limit) + return -EINVAL; + else + sch->limit = ctl->limit;
The dev->tx_queue_len is fundamentally non-sense since now almost every real NIC is multi-queue and qdisc has a completely different sch->limit. This is why I suggested you to simply avoid it in your code.
There is no standard way to use dev->tx_queue_len in kernel, so I can't claim your use is correct or not, but it still looks odd, other qdisc seems just uses as a default, rather than picking the smaller or bigger value as a cap.
Quoted 10 lines · Cong Wang
Documentation/networking/sch_skbprio.txt
Quoted 5 lines · Nishanth Devarajan
Documentation/networking/sch_skbprio.txt new file +0
-0We usually document each qdisc behavior in tc man pages in iproute2.
I don't mind you document it in kernel, but it kinda breaks the tradition.
We're going to move this text to tc man pages for v4.
Quoted 10 lines
Quoted 10 lines
Documentation/networking/sch_skbprio.txt new file +10
-0+static int skbprio_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +{ + struct skbprio_sched_data *q = qdisc_priv(sch); + struct tc_skbprio_qopt *ctl = nla_data(opt); + const unsigned int min_limit = 1; + + if (ctl->limit == (typeof(ctl->limit))-1) + sch->limit = max(qdisc_dev(sch)->tx_queue_len, min_limit); + else if (ctl->limit < min_limit)
Quoted 8 lines
Documentation/networking/sch_skbprio.txt
Quoted 3 lines
Documentation/networking/sch_skbprio.txt new file +3
-0+ return -EINVAL; + else + sch->limit = ctl->limit;The
dev->tx_queue_lenis fundamentally non-sense since now almost every real NIC is multi-queue and qdisc has a completely differentsch->limit. This is why I suggested you to simply avoid it in your code.
Would you be okay with a constant there? If so, we could just put 64
there. The optimal number is hardware dependent, but we don't know how to calculate it.
Quoted 4 lines
There is no standard way to use
dev->tx_queue_lenin kernel, so I can't claim your use is correct or not, but it still looks odd, other qdisc seems just uses as a default, rather than picking the smaller or bigger value as a cap.
The reason for the max(qdisc_dev(sch)->tx_queue_len, min_limit) is
to make sure that sch->limit is at least 1. We couldn't come up with a meaningful behavior for sch->limit being zero, so we defined the basis case of skbprio_enqueue() as sch->limit one. If there's a guarantee that qdisc_dev(sch)->tx_queue_len is always greater than zero, we don't need the max().
[ ]'s
Michel Machado
(Sorry for missing this email, it is lost in other discussions.)
Quoted 10 lines · Michel Machado
Quoted 4 lines · Cong Wang
The
dev->tx_queue_lenis fundamentally non-sense since now almost every real NIC is multi-queue and qdisc has a completely differentsch->limit. This is why I suggested you to simply avoid it in your code.Would you be okay with a constant there? If so, we could just put 64
there. The optimal number is hardware dependent, but we don't know how to calculate it.
Yes, sure, fq_codel uses 10240 already. :)
Quoted 6 lines
Quoted 5 lines
There is no standard way to use
dev->tx_queue_lenin kernel, so I can't claim your use is correct or not, but it still looks odd, other qdisc seems just uses as a default, rather than picking the smaller or bigger value as a cap.
Quoted 6 lines
The reason for the `max(qdisc_dev(sch)->tx_queue_len, min_limit)` isto make sure that
sch->limitis at least 1. We couldn't come up with a meaningful behavior forsch->limitbeing zero, so we defined the basis case ofskbprio_enqueue()assch->limitone. If there's a guarantee that qdisc_dev(sch)->tx_queue_len is always greater than zero, we don't need themax().
I think tx_queue_len could be 0. But again, why do you need to care about tx_queue_len being 0 or not here?
sch->limit could be 0 too, it means this qdisc should not queue any packets.
Thanks