-
Notifications
You must be signed in to change notification settings - Fork 3k
Networking update: general refactoring, unifying EMAC #5558
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
Conversation
@kjbracey-arm Review assignments are up to you |
Quite a few people should look at this. I can think of: @sg-, @geky, @c1728p9, @bulislaw, @SeppoTakalo, @mikaleppanen, @0xc0170 What I want reviewed at this point is the concept of the new Also check if we're happy with the mechanism for default EMAC and stack selection. Our current assumption is that the Rather hard to see what's going on in a GitHub web diff. You can get a clearer diff result in Git itself if you do a diff with Might be easiest just look at the end result, rather than the patch. I'll try and get some design documentation added to the description to help clarify this week. Another general conceptual concern - does more C++ to drivers increase binary blob compatibility headaches excessively? (cf #5546) In this case though, even #4079's C EMAC tweaks was a binary break in various ways - the C++ may not make things qualitatively worse. |
Maintaining binary compatibility may be difficult as virtual member functions are part of a data structure: the vtable. The pimpl idiom¹ ² may be used to work around this issue but it is not applicable in our case because it allocates memory. There is a good document in KDE Wiki that sumarize do's and dont's; the itanium ABI might be consulted to resolve all ambiguities. Is there a commitment to maintain binary compatibility in mbed OS ? RTX updates, cmsis updates, vendor SDK updates may just break it and it is out of our control with the current architecture. |
It is not out of our hands when we merge in those changes. |
@sg- Do we have a commitment to maintain binary - and not just API - compatibility in mbed OS ? |
We do have binary drivers within the source tree so how can we not commit to support them. |
@SeppoTakalo It is a software dependency problem. If the binary driver doesn't use mbed os APIs then it won't suffer of any binary compatibility issue. However if the binary driver exploits mbed OS APIs then breaking mbed OS binary compatibility may affect the binary driver; that has been seen in #5546 . A clear answer on binary compatibility rather than guesses might help us. Binary compatibility was broken in the past (like during the RTX2 update); it was known and it didn't resulted in major version bump. |
Realistically I think we'll inevitably hit some binary breakage on pretty much every minor version bump, and can endeavour to avoid it on patches with a little more care. Achieving more than that would require a significant redesign and much more care about the C++ - I'd say anyone using binary blobs should be prepared to recompile on each minor update. |
Very good guide, always visit it when in doubt
Patches should not have any breakages, period. @SeppoTakalo noted above in #5558 (comment) nicely.
If that was the case, that should have been sent to minor. We had cases when we broke it 😞 We should document this better . We are drifting away from networking update here, we can create a new issue to continue there. |
* @param size Size of memory to allocate | ||
* @param align Memory alignment requirements | ||
* @return Allocated memory struct, or NULL in case of error | ||
*/ | ||
emac_stack_mem_t *emac_stack_mem_alloc(emac_stack_t* stack, uint32_t size, uint32_t align); | ||
emac_stack_mem_t *emac_stack_mem_alloc(uint32_t size, uint32_t align); |
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.
Should there be an option to have an allocator per network stack? If not, this API will force all network stacks to use lwip's pbuf mechanism (or copy the data). From your pr description this will be changing anyway.
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, allocator absolutely needs to be per-stack, or this won't take off. The current mem API will need a little generalisation and "what exactly is this call specified to do?" work anyway, so we've yet to tackle it.
That's in contrast to the other APIs which remain largely unchanged apart from being objectified and C++ified.
I guess we stick with the assumption that each interface is only being used by 1 stack at once, so the interface knows how to pre-allocate its RX buffers.
(In the other system I did this stuff we did permit multiple stacks (IP/NetBIOS/Appletalk/...) to use an interface simultaneously, but everyone was forced to use the same central allocator.)
There is no requirement to maintain binary compatibility in mbed-os. If you are using mbed-os's public API from an application or library, you must recompile your binary if you are updating to a newer version of mbed-os. Each Driver class ( That being said, some libraries in mbed-os are called from mbed, but do not call into or use the mbed-os API. For example the binary form of nanostack did not need to be re-compiled on each mbed-os release because it didn't call into the mbed-os API. Instead that was done from source which wrapped nanostack. |
Added a second commit which might allow Wifi drivers to reduce boilerplate - inherit from "EMACInterface" to handle all the core stack attachment stuff and then they only need to implement the WiFi-specific connect/credential/scan methods from "WiFiInterface". Does mean a diamond virtual inheritance pattern. Too gnarly? |
Done, ff to the latest master (I could do the specific commit but should not matter here, to get the latest one?), let me know if that is a problem. |
Thanks! That didn't seem to clear up the display at first - don't know why - but did another rebase and it's fine. |
@kjbracey-arm Looks like another rebase is needed. |
9f8ba35
to
b6a9505
Compare
As we've introduced virtual inheritance to support EMACInterface, we can no longer use C-style casts or static_cast to downcast from NetworkInterface to more specific types. RTTI is disabled in the toolchains, so dynamic_cast is unavailables. Add virtual downcast methods to permit conversions to the 6 derived classes. Probably only needed for EMACInterface, WiFiInterface and EthInterface, but handles the set.
Make ETHERNET configuration the default if DEVICE_EMAC is present, instead of if FEATURE_LWIP is present. This limits it to targets which have been ported to the new EMAC API. Add LWIP feature to JSON config, as in principle the targets shouldn't be adding it themselves. Opens scope to having Nanostack-based tests. Disable tests for the Realtek and Wifi drivers that aren't ported yet.
I would like to restrict these to devices with "device_has": "EMAC", but the framework doesn't currently permit that. Revisit as more drivers are EMAC-enabled or if the framework changes.
Pending Nanostack EMAC work, disable the border router.
Suppress Odin W2 and Realtek Wi-fi drivers using .mbedignore
Pending EMAC driver update, these tests won't compile.
/morph build |
Build : SUCCESSBuild number : 1044 Triggering tests/morph test |
Let's see here... |
Exporter Build : SUCCESSBuild number : 725 |
Test : FAILUREBuild number : 852 |
Fix "connect twice" GreenTea test
Connect twice failures hopefully resolved now. Was a real bug introduced to the lwip connect logic by the C++-ification. |
/morph build |
Build : SUCCESSBuild number : 1058 Triggering tests/morph test |
Test : SUCCESSBuild number : 864 |
Exporter Build : SUCCESSBuild number : 737 |
All green ! This is now ready for integration to the feature branch |
Here's the next pass of #5202, with a major "spelling" rework into C++ following discussions with @sg-.
No huge conceptual changes, but the C++-ification does open up the flexibility. I think that's best summarised by
EthernetInterface
's constructor prototype:This is a pull request to
feature-emac
, with only the K64F driver transformed to the new API, so won't build for any other lwIP-based platform yet. It will be some time until the feature branch can be merged - it's a compatibility break for all lwIP and emac drivers.A number of notes in the commit message.
Nice diagrams to follow shortly.
The network stack
OnboardNetworkStack
OnboardNetworkStack
is an abstract class specialising the existingNetworkStack
, which is the application-facing thing that provides sockets. In the initial implementation there will be two of these:LWIP
andNanostack
.LWIP
is present in this PR.The main extra method is
This allows an EMAC-based driver to attach itself to a stack - the call gives back an
OnboardNetworkStack::Interface
, which is the stack's "handle" for this interface.To locate the default stack, we have
This will return either a
LWIP
orNanostack
(or other) object, depending on a JSON setting. By usingget_default_instance()
in a default function parameter, we can ensure the default stack is pulled in by the linker only if used.OnboardNetworkStack::Interface
This provides methods to support
EthernetInterface
or any other EMAC-based driver providing aNetworkInterface
, which is the application API.NetworkInterface
covers interfaces which can either be using an onboard stack or an offboard one. For those using an onboard stack, most of the work can be deferred to theOnboardNetworkStack::Interface
.Via this C++ objectification, the LWIP adaptation glue naturally becomes multiple-interface - all its static information is now resident in the
LWIP::Interface
objects created byLWIP::add_ethernet_interface
- see next section.Application-facing network drivers
EthernetInterface
EthernetInterface
is now the prototypical "just an EMAC" driver, implementing aNetworkInterface
using anEMAC
and anOnboardNetworkStack
. There's no actual code involved - it derives fromEMACInterface
, which provides the base implementation.Construction forms are:
EthernetInterface net;
- default stack, default EMACEthernetInterface net(my_emac);
- default stack, specified EMACEthernetinterface net(my_emac, LWIP::get_instance());
- LWIP, specified EMACEthernetInterface::connect
is basicallyAnd other bits are simple glue like:
Other EMAC-based NetworkInterfaces
EMACInterface
is a "base" EMACNetworkInterface
, from which EMAC Wi-Fi drivers can derive, rather than providing theNetworkInterface
->OnboardNetworkStack::Interface
glue themselves, as they currently do forNetworkInterface
->mbed_lwip_xxx
.They can provide their own overridden
connect
methods to configure their MAC, which do initial set-up and then callEMACInterface::connect()
to bring up the network stack.EMAC drivers
The EMAC API is respelt into C++ without significant change - an EMAC driver must now supply an implementation of the abstract
EMAC
class. This replacesemac_interface_t
andemac_interface_ops_t
, in a way that allows full stack/interface implementation independence.Memory API
The memory API used by EMAC drivers (
emac_stack_mem.h
) is not yet changed in this PR. PR#5750 transforms it so that theOnboardNetworkStack
provides gives the EMAC reference to aEMACMemoryManager
object providing the facilities. This is necessary to permit two stacks to co-exist in the tree withoutFEATURE_XXX
flagging.Targets
To permit plain
EthernetInterface
to work without parameters, a target must implement the factory methodEMAC::get_default_instance()
, eg:My thought is here that a target would provide this weakly, so a module or application could override it at normal strength.
Flagging
DEVICE_EMAC
is retained to indicate thatEMAC::get_default_instance()
is provided by the target. It may be tested by target-specific code to check whether to compile its driver - eg k64f_emac.cpp checks it so it only compiles on relevant Freescale platforms.DEVICE_EMAC
should not be set other than by the target - eg by a module providingEMAC::get_default_instance()
. And it is always possible to useEthernetInterface
andEMACInterface
with a manually specified EMAC.Question - do we need a flag to indicate
EMAC::get_default_instance()
is provided at a higher level, eg to gate building tests?