Skip to content

net_core: Decide about l2-processing based on l2_processed-flag #93050

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ClaCodes
Copy link
Contributor

@ClaCodes ClaCodes commented Jul 12, 2025

Use the l2_processed-flag to decide whether a network packet needs to be processed by an L2-handler. This could be used in the future to requeue packets for later processing by a different traffic class queue.

Note: this would break all out-of-tree code, that assumed setting reassembled is enough for the packet to be not processed by l2 handlers. Not sure, if this is a valid concern?

Finally goal is to reach something like, so that processing of packets can be deferred easily:

void process_data(struct net_pkt *pkt) {
    // ...
    if (!net_pkt_is_l2_processed(pkt)) {
        process_l2(pkt);
        net_pkt_set_l2_processed(pkt, true);
        bool updated = update_priority(pkt);
        if (updated) {
            net_queue_rx(net_pkt_iface(pkt), pkt);
            return;
        }
    }
    // ...
    if (!net_pkt_is_l3_processed(pkt)) {
        process_l3(pkt);
        net_pkt_set_l3_processed(pkt, true);
        bool updated = update_priority(pkt);
        if (updated) {
            net_queue_rx(net_pkt_iface(pkt), pkt);
            return;
        }
    }
    // ...
    if (!net_pkt_is_l4_processed(pkt)) {
        process_l4(pkt);
        net_pkt_set_l4_processed(pkt, true);
        bool updated = update_priority(pkt);
        if (updated) {
            net_queue_rx(net_pkt_iface(pkt), pkt);
            return;
        }
    }
}

Maybe instead:

    process_ll(pkt);
    process_transport(pkt); // net_ipvX_input
    process_connection(pkt); // net_conn_input

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.

Generally no objections, but I would split the loopback flag change from other changes into as separate commit.

@ClaCodes
Copy link
Contributor Author

Generally no objections, but I would split the loopback flag change from other changes into as separate commit.

  • done
  • rebased

@@ -493,6 +483,7 @@ static void net_rx(struct net_if *iface, struct net_pkt *pkt)
#ifdef CONFIG_NET_L2_DUMMY
if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
net_pkt_set_loopback(pkt, true);
net_pkt_set_l2_processed(pkt, true);
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to break AF_PACKET/SOCK_RAW sockets processing on loopback, some tests use this combination and now fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to find a solution for AF_PACKET/SOCK_RAW. It can not stay unconditionally at the begining of process_data, as a packet will soon pass there multiple times potentially (unless we want the packet to be inputted many times into a AF_PACKET/SOCK_RAW, which I assume we do not want). When we have deffered packet processing a packet may go through process_data many times with different stages of its processing. Initially, maybe l2_processed is false, then on second pass, l2_processed is true, but l3_processed is false, .... That is at least my vision.

Then, maybe we could also move this into the layer 2 if:

	if (!net_pkt_is_l2_processed(pkt)) {
		/* forward packets to SOCK_RAW packet sockets. */
		ret = net_packet_socket_input(pkt, ETH_P_ALL);
		if (ret != NET_CONTINUE) {
			return ret;
		}

		ret = net_if_recv_data(net_pkt_iface(pkt), pkt);
		net_pkt_set_l2_processed(pkt, true);
                // ...

But this will of course equally break the tests, that want to send a loopback packet and expect it to be passed to AF_PACKET/SOCK_RAW. Do locally routed packets have to be inputed in those sockets?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: We also have tests, that check that reassembled packets reach the raw sockets...

Not sure, what to do with this either?

Copy link
Contributor Author

@ClaCodes ClaCodes Jul 16, 2025

Choose a reason for hiding this comment

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

One more note (sorry for spam): we may even want to input the packet into raw socket only after it was processed by L2. See zpacket_set_source_addr where it currently has to do ethernet specific address parsing, because the packet was not yet processed by L2, when it was inputed into the raw socket.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note: We also have tests, that check that reassembled packets reach the raw sockets...

Which tests are you referring to, I don't see any packet sockets being used in IP fragmentation tests?

we may even want to input the packet into raw socket only after it was processed by L2. See zpacket_set_source_addr where it currently has to do ethernet specific address parsing, because the packet was not yet processed by L2, when it was inputed into the raw socket.

I don't think that's a viable approach (at least not without some even further refactoring) as L2 strips the L2 header, which is expected to be present in packet with SOCK_RAW socket.

We need to find a solution for AF_PACKET/SOCK_RAW. It can not stay unconditionally at the begining of process_data, as a packet will soon pass there multiple times potentially (unless we want the packet to be inputted many times into a AF_PACKET/SOCK_RAW, which I assume we do not want). When we have deffered packet processing a packet may go through process_data many times with different stages of its processing. Initially, maybe l2_processed is false, then on second pass, l2_processed is true, but l3_processed is false, .... That is at least my vision.

Then perhaps we need yet another flag on the packet similar to l2_processed, something like raw_processed to ensure packet is delivered only once. For sure we do not want the packet socket to receive multiple copies of the same packet.

Do locally routed packets have to be inputed in those sockets?

To be fair, I'm not sure if they have to (we currently only seem to use this "feature" in tests) but at the same time I'm not convinced on limiting functionality because of implementation details. Probably would be good to check how it works in other systems (with Linux in mind), i.e. whether AF_PACKET/SOCK_RAW socket is able to receive loopback packets.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Which tests are you referring to, I don't see any packet sockets being used in IP fragmentation tests?

My bad, I was confused.

I don't think that's a viable approach (at least not without some even further refactoring) as L2 strips the L2 header, which is expected to be present in packet with SOCK_RAW socket.

Ok, makes sense.

Then perhaps we need yet another flag on the packet similar to l2_processed, something like raw_processed to ensure packet is delivered only once. For sure we do not want the packet socket to receive multiple copies of the same packet.

Ok, will go this direction in future PRs. We can discuss then in detail.

@@ -92,8 +82,9 @@ static inline enum net_verdict process_data(struct net_pkt *pkt)
return NET_DROP;
}

if (!net_pkt_is_loopback(pkt) && !locally_routed) {
if (!net_pkt_is_l2_processed(pkt)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Referring to the previous commit, perhaps this should check for both flags, i.e.:

if (!net_pkt_is_loopback(pkt) && !net_pkt_is_l2_processed(pkt)) {

instead of setting l2_processed flag for loopback packets?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, will do but see comment below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

2bd0fc4 reverts and tries a different approach.

Store the flag in the packet meta-data so that processing may be deferred
if necessary.

Signed-off-by: Cla Mattia Galliard <clamattia@gmail.com>
Copy link
Contributor Author

@ClaCodes ClaCodes left a comment

Choose a reason for hiding this comment

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

Thanks for the quick feedback.

@@ -493,6 +483,7 @@ static void net_rx(struct net_if *iface, struct net_pkt *pkt)
#ifdef CONFIG_NET_L2_DUMMY
if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
net_pkt_set_loopback(pkt, true);
net_pkt_set_l2_processed(pkt, true);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to find a solution for AF_PACKET/SOCK_RAW. It can not stay unconditionally at the begining of process_data, as a packet will soon pass there multiple times potentially (unless we want the packet to be inputted many times into a AF_PACKET/SOCK_RAW, which I assume we do not want). When we have deffered packet processing a packet may go through process_data many times with different stages of its processing. Initially, maybe l2_processed is false, then on second pass, l2_processed is true, but l3_processed is false, .... That is at least my vision.

Then, maybe we could also move this into the layer 2 if:

	if (!net_pkt_is_l2_processed(pkt)) {
		/* forward packets to SOCK_RAW packet sockets. */
		ret = net_packet_socket_input(pkt, ETH_P_ALL);
		if (ret != NET_CONTINUE) {
			return ret;
		}

		ret = net_if_recv_data(net_pkt_iface(pkt), pkt);
		net_pkt_set_l2_processed(pkt, true);
                // ...

But this will of course equally break the tests, that want to send a loopback packet and expect it to be passed to AF_PACKET/SOCK_RAW. Do locally routed packets have to be inputed in those sockets?

@@ -92,8 +82,9 @@ static inline enum net_verdict process_data(struct net_pkt *pkt)
return NET_DROP;
}

if (!net_pkt_is_loopback(pkt) && !locally_routed) {
if (!net_pkt_is_l2_processed(pkt)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, will do but see comment below.

@ClaCodes ClaCodes force-pushed the main branch 2 times, most recently from fd65f8b to 54a1036 Compare July 15, 2025 20:21
Use the l2_processed-flag to decide whether a network packet needs to be
processed by an L2-handler. This could be used in the future to requeue
packets for later processing by a different traffic class queue.

Signed-off-by: Cla Mattia Galliard <clamattia@gmail.com>
@ClaCodes ClaCodes force-pushed the main branch 2 times, most recently from 2bd0fc4 to 2730c6c Compare July 16, 2025 06:18
Specify the socket type, when inputing a packet into a packet-socket.

Signed-off-by: Cla Mattia Galliard <clamattia@gmail.com>
Copy link

@ClaCodes
Copy link
Contributor Author

On the meaning of l2_processed

There are basically two possible interpretation of the flag at the moment:

  • Does the flag mean, that l2-processing is no longer needed and so the respective step in process_data can be skipped
  • or does it mean, that the l2-header information is present in the pkts meta data?

In the first case (I am assuming in this PR), the users have to set the flag (for reassembled and for loopback), in the second case, it is set l2_processing when the header information is put in the packets meta-data and we need to check the other flags as well to determine, whether L2-processing is necessary (!is_loopback && !is_reassembed && !is_l2_processed).

I will revert if decision is made for the second interpretation.

@ClaCodes
Copy link
Contributor Author

See also: #93245

@rlubos
Copy link
Contributor

rlubos commented Jul 17, 2025

There are basically two possible interpretation of the flag at the moment:

  • Does the flag mean, that l2-processing is no longer needed and so the respective step in process_data can be skipped
  • or does it mean, that the l2-header information is present in the pkts meta data?

Those two are not contradictory IMO, and actually I think both assumptions are correct, which I think can be summarized with a single sentence "L2 header is not longer present in the packet" and that indicates that both:

  • All meta-data (proto type, LL address etc.) should be set in the packet,
  • L2 processing is not only no longer needed, but is not really possible anymore as there's no L2 header to work with.

@clamattia
Copy link
Contributor

I think both assumptions are correct

Not sure, example:

  • loopback (L2 processing is not needed, but AFAIK no LL address meta-data is set in the header)
  • same with reassembled

@rlubos
Copy link
Contributor

rlubos commented Jul 17, 2025

  • loopback (L2 processing is not needed, but AFAIK no LL address meta-data is set in the header)

I didn't dig into details, but there's definitely some logic for copying the proto and LL address for the loopback case:

net_pkt_set_ll_proto_type(pkt, ETH_P_IP);
copy_ll_addr(pkt);

same with reassembled

That should probably be revisited then, IMHO reassembly code should set any metadata that might be needed by upper layers.

@clamattia
Copy link
Contributor

IMHO reassembly code should set any metadata that might be needed by upper layers.

Maybe my bad. Will dig into it.

@clamattia
Copy link
Contributor

Those two are not contradictory IMO, and actually I think both assumptions are correct

That would be ideal and least confusing.

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