-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
base: main
Are you sure you want to change the base?
net: Extend the protocol handling in Ethernet #84037
Conversation
da49086
to
ef8c9e5
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.
LGTM, please have a look at some ideas and comments from my side.
subsys/net/lib/ptp/ptp.c
Outdated
return NET_CONTINUE; | ||
} | ||
|
||
NET_L3_REGISTER(arp, NET_ETH_PTYPE_PTP, ptp_recv); |
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?
NET_L3_REGISTER(arp, NET_ETH_PTYPE_PTP, ptp_recv); | |
NET_L3_REGISTER(ptp, NET_ETH_PTYPE_PTP, ptp_recv); |
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, I noticed it too and it should already fixed by latest version.
include/zephyr/net/net_core.h
Outdated
/** Is L2 address correct */ | ||
bool (*l2_addr_check)(struct net_if *iface, | ||
uint16_t ptype, | ||
struct net_pkt *pkt, | ||
struct net_linkaddr *dst_lladdr); |
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 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?
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 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.
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.
- 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.
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.
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.
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 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( |
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.
Here you could check the is_group
, I believe.
handled = true; | ||
break; | ||
} else { | ||
goto drop; |
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.
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.
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.
What is the use case for having multiple handlers for a same ptype, it is not clear to me why would we allow that.
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 do not see a a usecase either right now.
Maybe it would just be helpful to avoid misconfiguration, if possible.
subsys/net/l2/ethernet/ethernet.c
Outdated
#endif | ||
|
||
#ifdef CONFIG_NET_ARP | ||
static enum net_verdict ethernet_arp_recv(struct net_if *iface, |
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.
Maybe this could be moved to the arp file?
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.
Could be, I will check it.
include/zephyr/net/net_core.h
Outdated
#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, \ |
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.
One optimization could be to sort these on the ptype
value for faster lookups.
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.
Could you elaborate this comment more, I thought that there is not much possibilities to say what order the linker places these.
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 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.
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.
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?
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.
Sadly not :(
include/zephyr/net/net_core.h
Outdated
bool (*l2_addr_check)(struct net_if *iface, | ||
uint16_t ptype, | ||
struct net_pkt *pkt, | ||
struct net_linkaddr *dst_lladdr); |
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.
Not with a usecase in mind, but maybe pass both source and destination address?
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); |
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 removed the extra address checker to simplify things and refactored the code so the link address parameter is not needed any more.
subsys/net/l2/ethernet/gptp/gptp.c
Outdated
uint16_t ptype, | ||
struct net_pkt *pkt, | ||
struct net_linkaddr *dst_lladdr) | ||
{ |
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.
Missing ARG_UNUSED(iface);
, same for other arguments.
subsys/net/l2/ethernet/lldp/lldp.c
Outdated
uint16_t ptype, | ||
struct net_pkt *pkt, | ||
struct net_linkaddr *dst_lladdr) | ||
{ |
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.
Same here.
ef8c9e5
to
8f280f5
Compare
|
include/zephyr/net/ethernet.h
Outdated
@@ -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 */ | |||
|
|||
|
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.
🤦 will remove this extra empty line in next version
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.
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( |
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.
Are you intentionally checking lldp
here?
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, 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)) { |
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.
Would it be worth checking, that l3->handler!=NULL
?
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 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]>
613cd7b
8f280f5
to
613cd7b
Compare
|
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