-
Notifications
You must be signed in to change notification settings - Fork 2k
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
netdev: Initial implementation of a more layered approach to netdev #8198
Conversation
I'd like to also get some feedback on this by @haukepetersen and @kaspar030. |
Why is there a need to distinguish between netdev_t and netdev_layer_t? By having them the same it will be interchangeable to add for example a software CSMA layer, or a duty cycling MAC layer on top of any device without the upper layer caring at all. |
From what I can see from the model (and the implementation): because |
Or do you mean, that it could have a benefit for physical devices to have next pointer? |
I meant why bother having two types to save on RAM for a single pointer? Most systems have one, max two physical interfaces, so it's only a matter of 2-8 bytes depending on platform. |
Makefile.dep
Outdated
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) | ||
USEMODULE += netdev_default | ||
USEMODULE += gnrc_netif | ||
endif | ||
|
||
ifneq (,$(filter netdev_ieee802154,$(USEMODULE))) | ||
ifneq (,$(filter netdev_layer_ieee802154,$(USEMODULE))) |
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.
Independent from the separate type discussion @gebart started: I would argue that a rename of netdev_ieee802154
and netdev_eth
isn't really 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.
Yeah, I agree on that, I came to the same conclusion after I had to rename half of the ifdefs scattered through gnrc_netif and nib
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.
Reverted "new" netdev_layer_(eth|ieee802154) files and reworked netdev_(eth|ieee802154) instead.
I don't really have an opinion on that, so whatever seems more suitable for the rest: go ahead with it. |
I would however prefer the pointer renamed to something other than |
While I agree that those 2-8 bytes might not matter, I'm not yet sure whether there is a real advantage besides removing some casts to this. Main advantage I can think of now is that it gives a clear indication when the end of the stack is reached (
|
The more I think about this idea, the more I like it. With this approach it will be possible to insert arbitrary hooks into the packet processing, for example insert a new layer between the netdev and the network layer to add artificial delays or packet drops to allow testing of lossy links on the local computer. |
Oh, and MAC layers can be made network stack independent by writing them as netdev layers, like @kaspar030 suggested before. Big thumbs up from me for the general idea, I did not look at the implementation details yet. |
To me, the main problem here is that with netdev, the frame is already in iovec format. I think it is easier to do packet manipulation and inspection while the packet is still handled as a chain of pktsnips. For now I think it is best to keep these layers to functionality that doesn't work on a specific set of frames, such as the artificial delay or random drop layers proposed by @gebart. |
I've removed the I would like to remove sidenote: the null layer included as example and for testing is not functional at the moment :( |
... or still. :)
That might be. But it is definitely easier to keep a network stack fast and memory efficient without pktsnips. |
What I was trying to say a few posts up is that it might be easier to move the L2 stats and the L2 filter completely to |
Added L2 netstats layer. For now only supports ethernet and IEEE802.15.4. I've named it netdev_stats, and made a circular dependency between the original netstats_l2 pseudomodule and this module to have both the old and the new name working (including all remaining "legacy" ifdefs). As most of the code is shareable between different L2 protocols, I've separated the differences by a case statement (only the multicast/unicast distinction needs it). I still need to add a few ifdefs there to only include the individual cases when the netdev code for that layer is included. |
It might be beneficial to iron out a concept before trying to keep the implementation up-to-date with the discussion... Makes it easier to only see the differences to the headers while discussing, and saves you the constant updating of actual code... 😉 |
This brings back an idea I've had for a while: how about refactoring
The benefits of an extra |
I just relized that this is already the case. ;) Sorry for the noise. |
What's the next step here? For now I've only tried to tackle the how to implement layered netdev here, not (really) the allocation and configuration of layered netdev. Not sure if we want to do that in this PR. I can start cleaning this up (I think I missed some doxygen here and there), but I like to know if there are more comments on the general design here. |
drivers/include/net/netdev.h
Outdated
#ifdef MODULE_NETSTATS_L2 | ||
netstats_t stats; /**< transceiver's statistics */ | ||
#endif | ||
netdev_t *child; /**< ptr to the lower netdev layer */ |
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.
Somehow I'd choose parent as name, don't now why. Any reasoning for "child"?
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 think this is due to my mental image of the layered stack as a literal stack of layers, the bottom one being the hardware driver and everything on top adding functionality. A packet being transmitted is handed down starting at the upper most layer to the layer below it, thus, from the parent layer to the child layer.
If you think parent (or upper/lower as stated below) is more clear to other people, I don't mind changing it. The goal here is of course to have something that is as intuitive as possible.
drivers/include/net/netdev.h
Outdated
* @return `< 0` on error, 0 on success | ||
*/ | ||
int netdev_get_pass(netdev_t *dev, netopt_t opt, void *value, size_t max_len); | ||
|
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.
extra newline
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.
Also for the other comments, I'll give this whole thing a large cleanup as soon as I have time, probably not tomorrow, but somewhere this week.
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.
And fixed now :)
drivers/include/net/netdev.h
Outdated
*/ | ||
void netdev_event_cb_pass(netdev_t *dev, netdev_event_t event); | ||
|
||
|
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.
extra newline
drivers/include/net/netdev.h
Outdated
* @brief Passthrough event callback function. | ||
* | ||
* @param[in] dev network device descriptor | ||
* @param[in] event type of the event |
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.
indent off
drivers/netdev_layer/netdev_layer.c
Outdated
#include "net/netdev.h" | ||
#include "assert.h" | ||
|
||
netdev_t *netdev_add_layer(netdev_t *top, netdev_t *netdev) { |
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 and below: { goes to next line
8470fc6
to
a9e649d
Compare
Reworded the commit message a bit to make it sound less generic |
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.
ACK
The comments and concernes were addressed, so I think this is okay.
Nope, please wait. |
Apparently GitHub's labeling system is not concurrency-safe ^^ |
a9e649d
to
2fd37c0
Compare
Fixed murdock complaints |
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.
Actually, I found another thing
drivers/netdev_layer/netdev_layer.c
Outdated
{ | ||
netdev_t *cur_dev = (netdev_t *)dev->context; | ||
|
||
cur_dev->event_callback((netdev_t *)cur_dev, event); |
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.
dev->context
is void *
so casting wouldn't be necessary, but you are casting first to netdev_t *
, store it in a netdev_t *
variable which you then again cast to netdev_t *
;-).
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.
Ack, will fix tomorrow morning
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.
Fixed
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.
ACK from my side.
Split out this looks nicely unintrusive. ;)
drivers/include/net/netdev/layer.h
Outdated
*/ | ||
static inline netdev_t *netdev_add_layer(netdev_t *top, netdev_t *dev) | ||
{ | ||
assert(top != 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.
This assert could also check for dev != 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 can't think of a reason why it should ever be NULL
, so I've added 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.
how about assert(top && dev);
?
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 think I prefer to keep them splitted, as it makes it slightly easier to determine which case triggered an assertion (dev == NULL
or top == NULL
). I can of course rewrite it to
assert(top);
assert(dev);
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
edit I mean, as you like, this is nitpicking. :)
Addressed the remarks |
please squash! |
66e402e
to
8a63b88
Compare
Added the assertion "rewrite" and squashed |
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.
ACK
@bergzand are your old ports for IEEE 802.15.4 and/or Ethernet still available for this somewhere? Are you planning to adapt them in the near future? |
First approach to have a more layered netdev (#7736). For now I have rebuild the netdev_ieee802154 and netdev_eth files to a layered setup. the l2filter and netstats are not yet implemented in the layered approach and remain implemented as before.
UML
I've adjusted the UML diagram a bit to what I think gives more flexibility in the long run:

I've decided to extend
netdev_t
instead. This way the callback can also be propagated back through all layers (for example required for a software frame retransmission implementation, or L2 statistics). The context pointer from thenetdev_t
is reused as the pointer to the layer above. It was already used in this way, only now it points to the previousnetdev_layer_t
object and for the last layer it points back to thegnrc_netif_t
object.Current implementation allows upper layers to override functionality from lower layers. This could be useful in the case of the software retransmissions where the number of retransmissions implemented by the driver needs to be masked.
Data Allocation
Data is allocated on the stack of the netif thread. I've added a function pointer to the
gnrc_netif_create
function. This function is first called and is expected to callgnrc_netif_thread
. This bootstrap function can push all necessary structs required for the intermediate layer on the stack, add them as layers, add a reference to the top layer to thegnrc_netif_t
object and call thegnrc_netif_thread
function to start the "real" thread part.This is the easiest way to add these netdev_layered_t objects in a semi-dynamic (non-configurable) way. I don't consider this the permanent way to allocate these structs, but as a PoC it should suffice.
Configuration
Todo
WIP