Skip to content
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: Extend the protocol handling in Ethernet #84037

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jukkar
Copy link
Member

@jukkar jukkar commented Jan 15, 2025

Allow user to specify protocol extensions when receiving data from Ethernet network. This means that user can register L3 protocol handler using NET_L3_REGISTER() with the desired protocol type. Ethernet code will then call the handler if such a protocol type packet is received. This is currently only implemented for Ethernet. The original IPv4 and IPv6 handling is left intact even if they can be considered to be L3 layer protocol. This could be changed in the future if needed so that IPv4 and IPv6 handling could be made pluggable protocols

Copy link
Contributor

@clamattia clamattia left a comment

Choose a reason for hiding this comment

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

LGTM, please have a look at some ideas and comments from my side.

return NET_CONTINUE;
}

NET_L3_REGISTER(arp, NET_ETH_PTYPE_PTP, ptp_recv);
Copy link
Contributor

Choose a reason for hiding this comment

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

typo?

Suggested change
NET_L3_REGISTER(arp, NET_ETH_PTYPE_PTP, ptp_recv);
NET_L3_REGISTER(ptp, NET_ETH_PTYPE_PTP, ptp_recv);

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I noticed it too and it should already fixed by latest version.

Comment on lines 174 to 178
/** Is L2 address correct */
bool (*l2_addr_check)(struct net_if *iface,
uint16_t ptype,
struct net_pkt *pkt,
struct net_linkaddr *dst_lladdr);
Copy link
Contributor

@clamattia clamattia Jan 16, 2025

Choose a reason for hiding this comment

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

I support the idea of this, but would it not be enough for the handler to check first and then to return NET_DROP if the address check fails. I believe the separate l2_addr_check function is maybe not necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

I considered it but there are couple of issues with that:

  • There is a check whether the packet is destined to this host. The check cannot be done after the handler function because it is too late, and it cannot be done before the handler function because then possible multicast addresses specific to some protocol (gPTP or LLDP) would be dropped.
  • We remove the L2 header from the net_buf before calling the handler function to allow the handler to directly use its payload. Then it is more cumbersome to check the Ethernet addresses in the handler function.

Copy link
Contributor

@clamattia clamattia Jan 16, 2025

Choose a reason for hiding this comment

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

  • There is a check whether the packet is destined to this host.

In my view, this is protocol specific (for example different multicast addresses).

If you are refering to :

	if (!net_eth_is_addr_broadcast((struct net_eth_addr *)lladdr->addr) &&
	    !net_eth_is_addr_multicast((struct net_eth_addr *)lladdr->addr) &&
	    !net_eth_is_addr_lldp_multicast(
		    (struct net_eth_addr *)lladdr->addr) &&
	    !net_eth_is_addr_ptp_multicast((struct net_eth_addr *)lladdr->addr) &&
	    !net_linkaddr_cmp(net_if_get_link_addr(iface), lladdr)) {

I think it maybe enough to drop there all frames that are not:

  • any multicast (net_eth_is_addr_group, i do not understand the name btw)
  • unicast with us as destination
  • broadcast

Specific multicast checks can then be done inside the handlers.

So the (adjusted) check can be done before, I would argue.

Then it is more cumbersome to check the Ethernet addresses in the handler function

But is it worth complicating the callback interface for this? I do not know. It is a balancing of interests.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe, if we pass src and dst to the handler as @pdgendt suggests, there is even less inconvenience and less an argument for having a separate function.

Copy link
Member Author

Choose a reason for hiding this comment

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

I revisited this and removed the additional address checker. This now expects that the mac group address bit is set for the special mac addresses we need to check.

if (!net_eth_is_addr_broadcast((struct net_eth_addr *)lladdr->addr) &&
!net_eth_is_addr_multicast((struct net_eth_addr *)lladdr->addr) &&
!net_eth_is_addr_lldp_multicast(
Copy link
Contributor

Choose a reason for hiding this comment

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

Here you could check the is_group, I believe.

handled = true;
break;
} else {
goto drop;
Copy link
Contributor

Choose a reason for hiding this comment

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

What if multiple handlers are registered for the same ptype?

Maybe we could say "it is not allowed", but then ideally this is checked at either BUILD-time or if not possible at init?

The alternative would be to just pass the packet by all the registered handlers and only drop it if all of them had a chance to look at it.

Copy link
Member Author

Choose a reason for hiding this comment

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

What is the use case for having multiple handlers for a same ptype, it is not clear to me why would we allow that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I do not see a a usecase either right now.
Maybe it would just be helpful to avoid misconfiguration, if possible.

#endif

#ifdef CONFIG_NET_ARP
static enum net_verdict ethernet_arp_recv(struct net_if *iface,
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this could be moved to the arp file?

Copy link
Member Author

Choose a reason for hiding this comment

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

Could be, I will check it.

#define NET_L3_REGISTER(_name, _ptype, _handler, _is_addr_ok) \
static const STRUCT_SECTION_ITERABLE(net_l3_register, \
NET_L3_GET_NAME(_name)) = { \
.ptype = _ptype, \
Copy link
Collaborator

Choose a reason for hiding this comment

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

One optimization could be to sort these on the ptype value for faster lookups.

Copy link
Member Author

Choose a reason for hiding this comment

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

Could you elaborate this comment more, I thought that there is not much possibilities to say what order the linker places these.

Copy link
Collaborator

@pdgendt pdgendt Jan 16, 2025

Choose a reason for hiding this comment

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

I have something in a downstream project, but realized it's only compatible with ld scripts. I've created a PR #84089 where you can create a named section using a numeric value to sort.

You would be able to use the ptype value to sort the sections.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I could add the ptype to the section name but as the value is defined as hex in ethernet.h the sections names look like

._net_l3_register.static.__net_l3_register_ARP_0x0806_
._net_l3_register.static.__net_l3_register_IPv4_0x0800_
._net_l3_register.static.__net_l3_register_IPv6_0x86dd_
._net_l3_register.static.__net_l3_register_gPTP_0x88f7_

Is your PR able to sort these?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sadly not :(

Comment on lines 175 to 178
bool (*l2_addr_check)(struct net_if *iface,
uint16_t ptype,
struct net_pkt *pkt,
struct net_linkaddr *dst_lladdr);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not with a usecase in mind, but maybe pass both source and destination address?

Suggested change
bool (*l2_addr_check)(struct net_if *iface,
uint16_t ptype,
struct net_pkt *pkt,
struct net_linkaddr *dst_lladdr);
bool (*l2_addr_check)(struct net_if *iface,
uint16_t ptype,
struct net_pkt *pkt,
struct net_linkaddr *src_lladdr,
struct net_linkaddr *dst_lladdr);

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed the extra address checker to simplify things and refactored the code so the link address parameter is not needed any more.

include/zephyr/net/net_core.h Show resolved Hide resolved
uint16_t ptype,
struct net_pkt *pkt,
struct net_linkaddr *dst_lladdr)
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing ARG_UNUSED(iface);, same for other arguments.

uint16_t ptype,
struct net_pkt *pkt,
struct net_linkaddr *dst_lladdr)
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here.

cmake/linker_script/common/common-rom.cmake Outdated Show resolved Hide resolved
include/zephyr/net/net_core.h Show resolved Hide resolved
subsys/net/l2/ethernet/ethernet.c Outdated Show resolved Hide resolved
@jukkar jukkar force-pushed the devel/net-l2-extend-ptype-handling branch from ef8c9e5 to 8f280f5 Compare January 16, 2025 14:37
@jukkar
Copy link
Member Author

jukkar commented Jan 16, 2025

  • Updated a new version and tried to address all the comments

@@ -119,6 +119,7 @@ struct net_eth_addr {
#define NET_ETH_MINIMAL_FRAME_SIZE 60 /**< Minimum Ethernet frame size */
#define NET_ETH_MTU 1500 /**< Ethernet MTU size */


Copy link
Member Author

Choose a reason for hiding this comment

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

🤦 will remove this extra empty line in next version

pdgendt
pdgendt previously approved these changes Jan 16, 2025
awojasinski
awojasinski previously approved these changes Jan 16, 2025
rlubos
rlubos previously approved these changes Jan 16, 2025
Copy link
Contributor

@clamattia clamattia left a comment

Choose a reason for hiding this comment

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

LGTM, just a observation and question to help avoid bugs under misconfiguration.


if (!(net_eth_is_addr_ptp_multicast(
(struct net_eth_addr *)net_pkt_lladdr_dst(pkt)->addr) ||
net_eth_is_addr_lldp_multicast(
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you intentionally checking lldp here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, gPTP has two well known multicast mac addresses that it needs to listen.

goto drop;
}
STRUCT_SECTION_FOREACH(net_l3_register, l3) {
if (l3->ptype != type || l3->l2 != &NET_L2_GET_NAME(ETHERNET)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be worth checking, that l3->handler!=NULL?

Copy link
Member Author

Choose a reason for hiding this comment

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

I will add build assert for this, it should be enough. It is very unlikely that the handler would not be set properly.

Allow user to specify protocol extensions when receiving data
from Ethernet network. This means that user can register L3
protocol handler using NET_L3_REGISTER() with the desired
protocol type. Ethernet code will then call the handler if
such a protocol type packet is received. This is currently
only implemented for Ethernet. The original IPv4 and IPv6
handling is left intact even if they can be considered to
be L3 layer protocol. This could be changed in the future
if needed so that IPv4 and IPv6 handling could be made
pluggable protocols.

Signed-off-by: Jukka Rissanen <[email protected]>
@jukkar jukkar dismissed stale reviews from rlubos, awojasinski, and pdgendt via 613cd7b January 17, 2025 07:12
@jukkar jukkar force-pushed the devel/net-l2-extend-ptype-handling branch from 8f280f5 to 613cd7b Compare January 17, 2025 07:12
@jukkar
Copy link
Member Author

jukkar commented Jan 17, 2025

  • CI fixes

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.

7 participants