-
Notifications
You must be signed in to change notification settings - Fork 8.2k
net: pkt_filter: Add priority filters to enable quality of service #93341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net: pkt_filter: Add priority filters to enable quality of service #93341
Conversation
26d64cc to
a4849f5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some initial feedback (on the topmost 2 commits).
c5f9c6c to
9bd6ae9
Compare
|
@rlubos + update_priority_l2(pkt);
+ if (!being_processed_by_correct_thread(pkt)) {
+ net_queue_rx(net_pkt_iface(pkt), pkt);
+ return NET_OK;
+ }For example after extracting the l2-header but before: I believe, that a loop and a if-else-chain or a switch would be more readable. Presumably the added computation cost is negligible? void process_data(struct net_pkt *pkt)
{
// switch would only work if raw packet sockets not needed for loop back etc.
switch (pkt->step) {
case STEP_1:
do_step_1();
return NET_CONTINUE;
case STEP_2:
do_step_2();
return NET_CONTINUE;
case STEP_3:
do_step_3();
return NET_CONTINUE;
// ...
}
}
void processing_data(struct net_pkt *pkt)
{
enum net_verdict verdict = NET_CONTINUE;
do {
verdict = process_data(pkt);
if (verdict != NET_CONTINUE) {
break;
}
update_prio(pkt, pkt->step);
if (!on_correct_thread(pkt)) {
net_queue_rx(pkt);
verdict = NET_OK;
}
} while (verdict == NET_CONTINUE);
// ... unref
}If we do not do this, it will be very hard to follow at which point the processing can be interrupted and then recontinued later. This may be an easy source of bugs. |
9bd6ae9 to
d88b7ac
Compare
d88b7ac to
80f5552
Compare
Note: contains all commits from #93246 and adds two commit |
80f5552 to
a69163e
Compare
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think packet rescheduling logic turned out pretty straightforward and looks fine, however I think we need to think on how would the priority updating look like in practice.
a69163e to
43cf73c
Compare
6cd1580 to
76d1a0d
Compare
|
76d1a0d to
3470ead
Compare
|
inverted boolean logic and fixed a problem introduced in earlier revision |
497c236 to
2f1e4f1
Compare
8b436fa to
7df34e2
Compare
samples/net/pkt_filter/src/main.c
Outdated
|
|
||
| /* Match ethernet packets for the precision time protocol (PTP) */ | ||
| static NPF_ETH_TYPE_MATCH(match_ptype_ptp, NET_ETH_PTYPE_PTP); | ||
| /* Match ethernet packets for the virual local area network (VLAN) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo s/virual/virtual/
samples/net/pkt_filter/src/main.c
Outdated
| static NPF_RULE(large_ipv4_pkt, NET_OK, ipv4_packet2, minsize_100, | ||
| match_iface_vlan2); | ||
| static NPF_SIZE_MIN(match_bigger_100, 100); | ||
| /* Match virutal internet protocol traffic */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo s/virutal/virtual/
samples/net/pkt_filter/src/main.c
Outdated
| static NPF_SIZE_MIN(match_bigger_100, 100); | ||
| /* Match virutal internet protocol traffic */ | ||
| static NPF_ETH_VLAN_TYPE_MATCH(match_ipv4_vlan, NET_ETH_PTYPE_IP); | ||
| /* Match virutal address resolution protocol (ARP) traffic */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Enable QoS by introducing priority-only packet filter rules that adjust packet priority (and thus TC queue) without deciding the final verdict, plus supporting infrastructure and a demonstrative Ethernet sample.
- Add NET_CONTINUE handling in packet filters and a new NPF_PRIORITY macro to set packet priority and continue evaluation
- Refactor TC thread priority computation with base/spread configs; add helpers and unify immediate-queue checks
- Introduce a QoS Ethernet sample, enhance shell filter output to show priority, queue, and thread priority
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| subsys/net/pkt_filter/base.c | Add NET_CONTINUE path to set packet priority and continue rule evaluation |
| include/zephyr/net/net_pkt_filter.h | Add priority field to npf_rule and a new NPF_PRIORITY macro |
| subsys/net/lib/shell/filter.c | Extend shell output to display priority-to-TC mapping and thread priorities |
| subsys/net/ip/net_tc.c | Replace lookup tables with computed thread priorities using base/spread; add exported helpers |
| subsys/net/ip/net_private.h | Add helper APIs and inline “immediate” checks for RX/TX |
| subsys/net/ip/net_if.c | Use new net_tc_tx_is_immediate helper |
| subsys/net/ip/net_core.c | Use new net_tc_rx_is_immediate helper |
| subsys/net/ip/Kconfig | Add configurable TX/RX thread priority spread options |
| samples/net/qos/ethernet/* | New QoS Ethernet sample demonstrating priority-based degradation and echo/command services |
| samples/net/pkt_filter/src/main.c | Add and order priority rules; comments and rule set updates for VLAN sample |
| samples/net/pkt_filter/prj.conf | Enable RX TCs and skip-for-high-prio in sample |
| doc/connectivity/networking/api/net_pkt_filter.rst | Document NET_CONTINUE semantics and NPF_PRIORITY usage with example |
| samples/net/qos/* (docs/yaml/cmake) | Sample metadata, build, and documentation |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| static NPF_PRIORITY(priority_rule_129, NET_PRIORITY_IC, npf_129); | ||
| static NPF_PRIORITY(priority_rule_130, NET_PRIORITY_NC, npf_130); | ||
|
|
||
| static uint32_t simulated_work_time; /* data race ! */ |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simulated_work_time is read/written from multiple threads (RX handler and TX send path) without synchronization, which is a data race. Use atomic_t with atomic_set/atomic_get, or protect access with a mutex; for example: replace with static atomic_t simulated_work_time; set with atomic_set(&simulated_work_time, work); and read with posix_cpu_hold((uint32_t)atomic_get(&simulated_work_time)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as I noted with the comment. But it is very unlikely, that is written while readers are active, and I would like to avoid them blocking each other.
samples/net/qos/ethernet/src/main.c
Outdated
|
|
||
| static int net_if_fake_send(const struct device *dev, struct net_pkt *pkt) | ||
| { | ||
| LOG_INF("sending service %d, pkt %p", net_pkt_ll_proto_type(pkt), pkt); |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
net_pkt_ll_proto_type() returns uint16_t, but the format specifier uses %d (signed int). Use %u or PRIu16 to avoid incorrect logging on larger values: LOG_INF("sending service %u, pkt %p", (unsigned)net_pkt_ll_proto_type(pkt), pkt);
| LOG_INF("sending service %d, pkt %p", net_pkt_ll_proto_type(pkt), pkt); | |
| LOG_INF("sending service %u, pkt %p", net_pkt_ll_proto_type(pkt), pkt); |
samples/net/pkt_filter/src/main.c
Outdated
|
|
||
| /* Match ethernet packets for the precision time protocol (PTP) */ | ||
| static NPF_ETH_TYPE_MATCH(match_ptype_ptp, NET_ETH_PTYPE_PTP); | ||
| /* Match ethernet packets for the virual local area network (VLAN) */ |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'virual' to 'virtual'.
samples/net/pkt_filter/src/main.c
Outdated
| static NPF_RULE(large_ipv4_pkt, NET_OK, ipv4_packet2, minsize_100, | ||
| match_iface_vlan2); | ||
| static NPF_SIZE_MIN(match_bigger_100, 100); | ||
| /* Match virutal internet protocol traffic */ |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'virutal' to 'virtual'.
samples/net/pkt_filter/src/main.c
Outdated
| static NPF_SIZE_MIN(match_bigger_100, 100); | ||
| /* Match virutal internet protocol traffic */ | ||
| static NPF_ETH_VLAN_TYPE_MATCH(match_ipv4_vlan, NET_ETH_PTYPE_IP); | ||
| /* Match virutal address resolution protocol (ARP) traffic */ |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'virutal' to 'virtual'.
include/zephyr/net/net_pkt_filter.h
Outdated
| struct npf_test *tests[]; /**< pointers to @ref npf_test instances */ | ||
| sys_snode_t node; /**< Slist rule list node */ | ||
| enum net_verdict result; /**< result if all tests pass */ | ||
| uint8_t priority; /**< priority in case of NET_CONTINUE */ |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Use the strong type enum net_priority for the priority field to improve type safety and self-documentation: change to enum net_priority priority; and adjust NPF_PRIORITY macro accordingly.
| uint8_t priority; /**< priority in case of NET_CONTINUE */ | |
| enum net_priority priority; /**< priority in case of NET_CONTINUE */ |
| int net_tc_tx_thread_priority(int tc) | ||
| { | ||
| /* Initial implementation just maps the traffic class to certain queue. | ||
| * If there are less queues than classes, then map them into | ||
| * some specific queue. | ||
| * | ||
| * Lower value in this table means higher thread priority. The | ||
| * value is used as a parameter to K_PRIO_COOP() or K_PRIO_PREEMPT() | ||
| * which converts it to actual thread priority. | ||
| * | ||
| * Higher traffic class value means higher priority queue. This means | ||
| * that thread_priorities[7] value should contain the highest priority | ||
| * for the TX queue handling thread. | ||
| * | ||
| * For example, if NET_TC_TX_COUNT = 8, which is the maximum number of | ||
| * traffic classes, then this priority array will contain following | ||
| * values if preemptive priorities are used: | ||
| * 7, 6, 5, 4, 3, 2, 1, 0 | ||
| * and | ||
| * 14, 13, 12, 11, 10, 9, 8, 7 | ||
| * if cooperative priorities are used. | ||
| * | ||
| * Then these will be converted to following thread priorities if | ||
| * CONFIG_NET_TC_THREAD_COOPERATIVE is enabled: | ||
| * -1, -2, -3, -4, -5, -6, -7, -8 | ||
| * | ||
| * and if CONFIG_NET_TC_THREAD_PREEMPTIVE is enabled, following thread | ||
| * priorities are used: | ||
| * 7, 6, 5, 4, 3, 2, 1, 0 | ||
| * | ||
| * This means that the lowest traffic class 1, will have the lowest | ||
| * cooperative priority -1 for coop priorities and 7 for preemptive | ||
| * priority. | ||
| */ | ||
| static const uint8_t thread_priorities[] = { | ||
| LISTIFY(NET_TC_TX_COUNT, PRIO_TX, (,)) | ||
| }; | ||
|
|
||
| BUILD_ASSERT(NET_TC_TX_COUNT <= CONFIG_NUM_COOP_PRIORITIES, | ||
| "Too many traffic classes"); | ||
|
|
||
| NET_ASSERT(tc < ARRAY_SIZE(thread_priorities)); | ||
|
|
||
| return thread_priorities[tc]; | ||
| int priority; | ||
| int thread_priority; | ||
|
|
||
| BUILD_ASSERT(BASE_PRIO_TX >= PRIO_SPREAD_TX * (NET_TC_TX_COUNT - 1)); | ||
| thread_priority = BASE_PRIO_TX - PRIO_SPREAD_TX * tc; | ||
|
|
||
| priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? | ||
| K_PRIO_COOP(thread_priority) : | ||
| K_PRIO_PREEMPT(thread_priority); | ||
| return priority; | ||
| } |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a runtime range check for tc to prevent out-of-range access in case of future callers: e.g., NET_ASSERT(tc >= 0 && tc < NET_TC_TX_COUNT); before using tc.
| int net_tc_rx_thread_priority(int tc) | ||
| { | ||
| static const uint8_t thread_priorities[] = { | ||
| LISTIFY(NET_TC_RX_COUNT, PRIO_RX, (,)) | ||
| }; | ||
| int priority; | ||
| int thread_priority; | ||
|
|
||
| BUILD_ASSERT(NET_TC_RX_COUNT <= CONFIG_NUM_COOP_PRIORITIES, | ||
| "Too many traffic classes"); | ||
| BUILD_ASSERT(BASE_PRIO_RX >= PRIO_SPREAD_RX * (NET_TC_RX_COUNT - 1)); | ||
| thread_priority = BASE_PRIO_RX - PRIO_SPREAD_RX * tc; | ||
|
|
||
| NET_ASSERT(tc < ARRAY_SIZE(thread_priorities)); | ||
|
|
||
| return thread_priorities[tc]; | ||
| priority = IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) ? | ||
| K_PRIO_COOP(thread_priority) : | ||
| K_PRIO_PREEMPT(thread_priority); | ||
| return priority; | ||
| } |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a runtime range check for tc to ensure it is within [0, NET_TC_RX_COUNT): e.g., NET_ASSERT(tc >= 0 && tc < NET_TC_RX_COUNT);
| config NET_TC_TX_THREAD_PRIO_SPREAD | ||
| int "Transmit traffic class thread priority spread" | ||
| default 1 |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constrain these integers with a non-zero positive range to avoid invalid configurations (e.g., add range 1 255 or an appropriate upper bound): range 1 255.
To enable quality-of-service (QoS) applications, allow filters to modify the priority of an incoming packet. This allows that processing can be done on tc-queue-threads with different priorities. Signed-off-by: Cla Mattia Galliard <[email protected]>
Add documentation for newly added priority rules. Signed-off-by: Cla Mattia Galliard <[email protected]>
Add some priority filters to the sample for demonstration purpose. Signed-off-by: Cla Mattia Galliard <[email protected]>
Allow to spread tc threads by more then one priority level and cleanup the computation of the priority. Signed-off-by: Cla Mattia Galliard <[email protected]>
Adjust table to print newly available information. Signed-off-by: Cla Mattia Galliard <[email protected]>
Add a sample, that shows the power of quality of service in Zephyr. Signed-off-by: Cla Mattia Galliard <[email protected]>
7df34e2 to
32b6758
Compare
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the future, try to avoid force pushing a rebase combined with changes. This makes the "compare" function in Github useless.
Will do. Sorry for causing overhead. |



Quality of Service for Ethernet
To enable quality-of-service (QoS) applications, add net_pkt_filters with
resultNET_CONTINUE, that allow to change the priority of an incoming packet dynamically. Then the processing of a network packet will happen on the respective traffic-class-queue. This enables a gradual degrading of availabilit of a service based on its priority (user application configurable).Results (Sample in this PR)
With QoS
c (x) := command service for priority x (high means higher priority)
e (x) := echo service for priority x (high means higher priority)
Without QoS
c (x) := command service for priority x (high means higher priority)
e (x) := echo service for priority x (high means higher priority)

Future Work
net_conn_input