Skip to content

Conversation

@ClaCodes
Copy link
Contributor

@ClaCodes ClaCodes commented Jul 18, 2025

Quality of Service for Ethernet

To enable quality-of-service (QoS) applications, add net_pkt_filters with result NET_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)

image

Without QoS

c (x) := command service for priority x (high means higher priority)

e (x) := echo service for priority x (high means higher priority)
image

Future Work

  • Implement deferring before net_conn_input
  • QoS for UDP
  • QoS for TCP

@ClaCodes ClaCodes force-pushed the feature/delay_processing branch 4 times, most recently from 26d64cc to a4849f5 Compare July 19, 2025 12:37
Copy link
Contributor

@rlubos rlubos left a 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).

@ClaCodes ClaCodes force-pushed the feature/delay_processing branch 5 times, most recently from c5f9c6c to 9bd6ae9 Compare July 24, 2025 16:36
@ClaCodes
Copy link
Contributor Author

@rlubos
I reverted along the lines of discussion.
Note that, if we go with the current approach of the RFC, we would have to add the snippet to multiple places:

+               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: STRUCT_SECTION_FOREACH(net_l3_register, l3) { such that for example arp packets can be offloaded on to another traffic class queue.
and after ip-header processing etc ...

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.

@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from 9bd6ae9 to d88b7ac Compare July 25, 2025 05:56
@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from d88b7ac to 80f5552 Compare August 16, 2025 09:03
@ClaCodes
Copy link
Contributor Author

  • Rebased

Note: contains all commits from #93246 and adds two commit

@sonarqubecloud
Copy link

Copy link
Contributor

@rlubos rlubos left a 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.

@tpambor
Copy link
Contributor

tpambor commented Sep 24, 2025

@ClaCodes Could you rebase this PR as the prerequisites #93246 and #93050 have been merged

@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from 6cd1580 to 76d1a0d Compare October 19, 2025 18:37
@ClaCodes
Copy link
Contributor Author

ClaCodes commented Oct 19, 2025

  • rebased
  • fixed nits and typos
  • Added to net filter shell command -> led to net: tc-mapping: Fix SKIP_FOR_HIGH_PRIO #97877 (additional commit)
  • Added priority filters to the existing sample in net/pkt_filter. Running net filter on that sample now gives:
Rule  Type        Verdict   Pkt-Prio  Queue  Thread-Prio  Tests
[ 1]  recv        CONTINUE         1      0            1  1    iface[1]
[ 2]  recv        CONTINUE         7      1         SKIP  2    iface[1],eth type[0x88f7]
[ 3]  recv        CONTINUE         2      0            1  2    iface[1],eth type[0x8100]
[ 4]  recv        CONTINUE         1      0            1  2    iface[2],eth vlan type[0x0806]
[ 5]  recv        CONTINUE         1      0            1  2    iface[3],eth vlan type[0x0806]
[ 6]  recv        OK             N/A    N/A          N/A  3    iface[2],eth vlan type[0x0800],size max[200]
[ 7]  recv        OK             N/A    N/A          N/A  3    iface[3],eth vlan type[0x0800],size min[100]
[ 8]  recv        OK             N/A    N/A          N/A  1    iface[1]
[ 9]  recv        OK             N/A    N/A          N/A  2    iface[2],eth vlan type[0x0806]
[10]  recv        OK             N/A    N/A          N/A  2    iface[3],eth vlan type[0x0806]
[11]  recv        DROP           N/A    N/A          N/A  0    

@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from 76d1a0d to 3470ead Compare October 19, 2025 18:50
@ClaCodes
Copy link
Contributor Author

inverted boolean logic and fixed a problem introduced in earlier revision

@ClaCodes ClaCodes force-pushed the feature/delay_processing branch 2 times, most recently from 497c236 to 2f1e4f1 Compare October 19, 2025 19:17
@ClaCodes ClaCodes force-pushed the feature/delay_processing branch 2 times, most recently from 8b436fa to 7df34e2 Compare October 20, 2025 04:38

/* 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) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo s/virual/virtual/

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 */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo s/virutal/virtual/

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 */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@pdgendt pdgendt requested a review from Copilot October 20, 2025 07:17
Copy link

Copilot AI left a 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 ! */
Copy link

Copilot AI Oct 20, 2025

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)).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

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.


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);
Copy link

Copilot AI Oct 20, 2025

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);

Suggested change
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);

Copilot uses AI. Check for mistakes.

/* 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) */
Copy link

Copilot AI Oct 20, 2025

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'.

Copilot uses AI. Check for mistakes.
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 */
Copy link

Copilot AI Oct 20, 2025

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'.

Copilot uses AI. Check for mistakes.
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 */
Copy link

Copilot AI Oct 20, 2025

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'.

Copilot uses AI. Check for mistakes.
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 */
Copy link

Copilot AI Oct 20, 2025

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.

Suggested change
uint8_t priority; /**< priority in case of NET_CONTINUE */
enum net_priority priority; /**< priority in case of NET_CONTINUE */

Copilot uses AI. Check for mistakes.
Comment on lines 176 to 189
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;
}
Copy link

Copilot AI Oct 20, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 190 to 204
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;
}
Copy link

Copilot AI Oct 20, 2025

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);

Copilot uses AI. Check for mistakes.
Comment on lines +298 to +300
config NET_TC_TX_THREAD_PRIO_SPREAD
int "Transmit traffic class thread priority spread"
default 1
Copy link

Copilot AI Oct 20, 2025

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.

Copilot uses AI. Check for mistakes.
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]>
@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from 7df34e2 to 32b6758 Compare October 20, 2025 20:03
@zephyrbot zephyrbot requested a review from jukkar October 20, 2025 20:05
@sonarqubecloud
Copy link

@ClaCodes
Copy link
Contributor Author

  • rebased
  • fix nits, suggestions and typos

@ClaCodes ClaCodes requested a review from tpambor October 20, 2025 20:13
Copy link
Contributor

@pdgendt pdgendt left a 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.

@jhedberg jhedberg merged commit 630a496 into zephyrproject-rtos:main Oct 21, 2025
27 checks passed
@ClaCodes
Copy link
Contributor Author

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.

@ClaCodes ClaCodes deleted the feature/delay_processing branch October 28, 2025 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants