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

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 6 times, most recently from f6a7bcb to 9f98615 Compare September 30, 2025 09:58
@zephyrbot zephyrbot requested a review from tejlmand September 30, 2025 10:00
@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from 9f98615 to e301b1b Compare October 11, 2025 20:40
@zephyrbot zephyrbot requested a review from rlubos October 11, 2025 20:42
@ClaCodes ClaCodes force-pushed the feature/delay_processing branch 6 times, most recently from 461d453 to 74a0377 Compare October 14, 2025 21:09
struct npf_rule {
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
Member

Choose a reason for hiding this comment

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

Please put the filter changes to a separate commit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done: 0f0ed9a

if (!pkt->frags) {
NET_DBG("Corrupted packet (frags %p)", pkt->frags);
net_stats_update_processing_error(net_pkt_iface(pkt));

Copy link
Member

Choose a reason for hiding this comment

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

unrelated change, please remove

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

net_stats_update_processing_error(
net_pkt_iface(pkt));
}

Copy link
Member

Choose a reason for hiding this comment

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

same here, and actually it is be preferred that there is an empty line after closing block (so the original code is ok)


return ret;
}
if (!being_processed_by_correct_thread(pkt)) {
Copy link
Member

Choose a reason for hiding this comment

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

like here, it would be preferred if there is empty line before the added if statement

return NET_DROP;
}


Copy link
Member

Choose a reason for hiding this comment

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

Please remove this extra empty line


SYS_SLIST_FOR_EACH_CONTAINER(rule_head, rule, node) {
if (apply_tests(rule, pkt) == true) {
if (rule->result == NET_CONTINUE) {
Copy link
Member

Choose a reason for hiding this comment

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

As mentioned earlier, the filter changes should be in separate commit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done: 0f0ed9a

#elif defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
#define BASE_PRIO_TX (CONFIG_NET_TC_NUM_PRIORITIES - 1)
#else
#define BASE_PRIO_TX (CONFIG_NET_TC_TX_COUNT - 1)
Copy link
Member

Choose a reason for hiding this comment

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

I did not understand the purpose of the commit net: tc: WIP/TEMP spread threads by more then 1 priority level. Anyway, the commit is WIP so I am assuming the idea comes in subsequent revisions.

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. I detailed the commit now.

Basically, without the commit the spacing between the tc-thread priorities must be one. The commit allows to modify it, so that the application writer may interleave with other threads. In the sample for example to alternate between rx and tx thread for nice result, that i now added to the description.

{
int res;
struct net_pkt *pkt = NULL;

Copy link
Member

Choose a reason for hiding this comment

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

extra empty line can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

copy_mac_to(dest);

pkt = net_pkt_rx_alloc_with_buffer(iface, MTU, AF_UNSPEC, 0, K_NO_WAIT);
if (!pkt) {
Copy link
Member

Choose a reason for hiding this comment

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

please write these checks like this if (pkt == NULL) { because of MISRA rule

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

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]>
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]>
@ClaCodes ClaCodes force-pushed the feature/delay_processing branch from 74a0377 to f068f37 Compare October 16, 2025 17:19
@zephyrbot zephyrbot requested a review from jukkar October 16, 2025 17:20
@ClaCodes ClaCodes changed the title RFC: net: core: Dynamic priority and deferred processing net: pkt_filter: Add priority filters to enable quality of service Oct 16, 2025
@ClaCodes
Copy link
Contributor Author

  • updated description and title

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 f068f37 to 48a6dea Compare October 16, 2025 17:37
@ClaCodes
Copy link
Contributor Author

  • any suggestion for the doc build?

Copy link

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.

5 participants