OpenThread Port
This PR provides a functional OpenThread implementation for Tock. This is not the final version of OpenThread in Tock, but represents a stable state. As is, this PR adds functionality for joining an existing network (as a minimal thread device), remaining attached to the network, and sending and receiving UDP packets.
The openthread_hello test application provides this functionality. The accompanying README provides in depth details to the current design and known issues that remain. To setup and test this device in a thread network, follow the instructions in the README.
Some issues that may occur if using/testing this current version:
- Child detachment: after ~7 minutes, the Tock device does not send a heart beat to remain attached to the network. This is occurring due to an alarm implementation issue.
- 6LoWPAN capsule panic: The 6LoWPAN capsule has a bug which on occasion causes a panic.
Todos:
- [x] Update makefiles and build structure from https://github.com/tock/libtock-c/tree/ot-bradjc
- [x] Need to actually figure out what flags we need set. I included some in the makefile while debugging, which may be redundant or unwanted. Should document which flags we are setting in the makefile(s). I think we don't set any flags, and just use the header files.
- [x] I had to hack around the cortex-m0 for mbedtls. I tried to make it clear how I modified the header file. I think it should be possible to use #undef and include the version from openthread instead, and then unset the asm flag on thumb1. (in ot-bradjc)
- [ ] I think we should create a new helper makefile in libtock-c/openthread that apps can include which setup all of the EXTERN_LIBS needed for openthread. This means we don’t have to copy the list to every ot app. We also can’t use the makefile.app because the extern_libs variable is not handled recursively.
- [x] Rename folder to just openthread (or I suppose libopenthread would also be consistent).
- [x] Simplify the platform directory, remove empty/unneeded files, remove folder nesting.
- [x] Rename from nrf52840 to tock in the platform library.
- [ ] Move config headers to their own directory. We should include them consistently in all of the builds.
So, just to clarify, there are basically two "real" bugs remaining in this current status, but neither are to do with any of the files added/touched in this PR.
One is in the kernel's 6lowpan driver (?).
One is in libtock-c's timer/alarm subsystem.
So, just to clarify, there are basically two "real" bugs remaining in this current status, but neither are to do with any of the files added/touched in this PR.
One is in the kernel's 6lowpan driver (?).
One is in libtock-c's timer/alarm subsystem.
Yes that is correct. (caveated by being unsure if the alarm bug is due to the OpenThread PAL, the libtock alarm subsystem, or a combination of both)
There is a brief PR I just created for the 15.4 capsule receive fixing a data offset miscalculation (so block on testing with this implementation until https://github.com/tock/tock/pull/3933 merges).
I'll copy the more extensive todo list from the README here so it is more easily viewable:
TODOs and Shortcomings
- The Tock Thread device disconnects from the network (i.e. does not send child update request and subsequently times out) after ~7 minutes. This bug has been traced to an issue with the alarm implementation but has not been resolved.
- The 6LoWPAN capsule on occassion panics (this behavior is observed semi frequently)
- The code size is quite large as is for the current implementation. There are numerous opportunities to reduce this (use hardware crypto instead of mbed crypto library).
- The openthread_hello
Makefilewill build all needed OpenThread and platform dependencies. However, themakebuild system, as is, does not rebuild the platform or OpenThread library if changes are made to either the platform or openthread directories.- Channel switching is not yet implemented
- The RSSI value is hard coded
Update: I believe I have addressed all comments either in the most recent commits or responded to them above. (with the exception of the copyright). Looking at other platforms that have ported openthread, it appears they use the openthread copyright statement. If someone else can confirm that this seems reasonable, I'll push changes including the copyright.
Update: I believe I have addressed all comments either in the most recent commits or responded to them above. (with the exception of the copyright). Looking at other platforms that have ported openthread, it appears they use the openthread copyright statement. If someone else can confirm that this seems reasonable, I'll push changes including the copyright.
I'm assuming you copied OpenThread code and then modified it, those files should then include the original copyright. If you made major changes you can append your copyright as well.
If you did a full re-write or a clean implementation then you can add a your own instead of OpenThread.
A lot of libtock-c doesn't specify anything in the file. Which I think means it's just copyrighted by you and dual licensed. It's probably best to be specific here as it's a mix between your work and OpenThread. That hopefully makes it clear
I would like to propose we compile openthread in advance and provide pre-compiled binaries (like we do with newlib/libcpp/picolib). I do not think we can provide a quality user experience with our current build system (and interfacing with openthread's build system) to compile the library at the same time as compiling apps. Thoughts?
I would like to propose we compile openthread in advance and provide pre-compiled binaries (like we do with newlib/libcpp/picolib). I do not think we can provide a quality user experience with our current build system (and interfacing with openthread's build system) to compile the library at the same time as compiling apps. Thoughts?
My preference is to use git submodules here, but I understand your frustrations / concerns @bradjc. In my opinion, the submodule is nice for openthread since the code base will likely not be altered and it serves as an explicit pointer to the detached head at the commit we set in the libtock-c repo. Additionally, the submodule in my opinion is more explicit for people navigating through the codebase in github as a pointer to the openthread repo.
If the consensus is for using a zip over the submodule, this would not be an issue as we could obtain a zip of the openthread repo. However, I think using an entirely precompiled binary would be a mistake. The biggest downside I see to precompiled binaries surrounds customization of openthread. OpenThread provides a high degree of customizable build flags that can be specified in config header files and also as CMake arguments. Using a precompiled binary pigeonholes us to our specific build configuration for OpenThread. A good example of this is the build flag for logging and whether to compile the Full Thread Device vs Minimal Thread Device.
If we remove the submodule, the entire library and repo will build using make from within the directory. The need to use make to kick off a script that then launches a CMake build system is convoluted, however, I do not see another way to allow for customizable OpenThread builds that use developer specific build flags.
Also just as a comment, the build system in the current state should work as expected. However, I need to push some changes to bring the branch in this PR up to date with changes we have made in the kernel.
A good example of this is the build flag for logging and whether to compile the Full Thread Device vs Minimal Thread Device.
I think for three examples we just build the library three or four times and include pre-compiled libraries for each (or maybe there are four: FTD/MTD x LOG/NOLOG). Are there more configurations that are realistic? We can compile everything in the open thread source, and allow the linker to remove dead code once it knows what the applications are. I understand the desire to support customizability, but 2-4 options is a pretty small number. Are there configurations which conflict? The master config option I've uses suggests openthread is ok with just compiling everything.
the entire library and repo will build using
makefrom within the directory
How are we going to support cortex-m0/m3/m4/m7/rv32i/rv32imac? And different versions of libcpp and newlib? Picolib? precompiling helps us avoid these issues by doing a more manual process offline. If we have users build on the fly, we need some make structure to handle all of that.
Using a precompiled binary pigeonholes us to our specific build configuration for OpenThread.
I think this is a good thing for most users who just want something that works. For others, we document everything, include scripts and makefiles, include dockerfiles that show the exact steps. Same as we do for newlib, which someone may want to customize and certainly can, but most people just need something that works.
I can't even build with cmake :(
./create_openthread-tock.sh
-- The C compiler identification is GNU 13.2.0
-- The CXX compiler identification is GNU 13.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: /usr/local/bin/arm-none-eabi-gcc
-- Check for working C compiler: /usr/local/bin/arm-none-eabi-gcc - broken
CMake Error at /usr/local/Cellar/cmake/3.25.2/share/cmake/Modules/CMakeTestCCompiler.cmake:70 (message):
The C compiler
"/usr/local/bin/arm-none-eabi-gcc"
is not able to compile a simple test program.
It fails with the following output:
Change Dir: /Users/bradjc/temp/libtock-c/openthread-tock/build/CMakeFiles/CMakeScratch/TryCompile-Ga8ybZ
Run Build Command(s):/usr/bin/make -f Makefile cmTC_dd9b9/fast && /Library/Developer/CommandLineTools/usr/bin/make -f CMakeFiles/cmTC_dd9b9.dir/build.make CMakeFiles/cmTC_dd9b9.dir/build
Building C object CMakeFiles/cmTC_dd9b9.dir/testCCompiler.c.obj
/usr/local/bin/arm-none-eabi-gcc -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -D_FORTIFY_SOURCE=2 -fPIC -mthumb -mfloat-abi=soft -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -mcpu=cortex-m4 -isystem ../lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/include -isystem ../lib/libtock-libc++-10.5.0/arm/arm-none-eabi/include/c++/10.5.0 -isystem ../lib/libtock-libc++-10.5.0/arm/arm-none-eabi/include/c++/10.5.0/arm-none-eabi -std=gnu11 -o CMakeFiles/cmTC_dd9b9.dir/testCCompiler.c.obj -c /Users/bradjc/temp/libtock-c/openthread-tock/build/CMakeFiles/CMakeScratch/TryCompile-Ga8ybZ/testCCompiler.c
Linking C executable cmTC_dd9b9
/usr/local/Cellar/cmake/3.25.2/bin/cmake -E cmake_link_script CMakeFiles/cmTC_dd9b9.dir/link.txt --verbose=1
/usr/local/bin/arm-none-eabi-gcc -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -D_FORTIFY_SOURCE=2 -fPIC -mthumb -mfloat-abi=soft -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -mcpu=cortex-m4 -isystem ../lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/include -isystem ../lib/libtock-libc++-10.5.0/arm/arm-none-eabi/include/c++/10.5.0 -isystem ../lib/libtock-libc++-10.5.0/arm/arm-none-eabi/include/c++/10.5.0/arm-none-eabi -std=gnu11 -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -D_FORTIFY_SOURCE=2 -fPIC -mthumb -mfloat-abi=soft -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -mcpu=cortex-m4 -isystem ../lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/include -isystem ../lib/libtock-libc++-10.5.0/arm/arm-none-eabi/include/c++/10.5.0 -isystem ../lib/libtock-libc++-10.5.0/arm/arm-none-eabi/include/c++/10.5.0/arm-none-eabi -specs=nano.specs -specs=nosys.specs CMakeFiles/cmTC_dd9b9.dir/testCCompiler.c.obj -o cmTC_dd9b9
arm-none-eabi-gcc: fatal error: cannot read spec file 'nano.specs': No such file or directory
compilation terminated.
make[2]: *** [cmTC_dd9b9] Error 1
make[1]: *** [cmTC_dd9b9/fast] Error 2
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:34 (project)
-- Configuring incomplete, errors occurred!
See also "/Users/bradjc/temp/libtock-c/openthread-tock/build/CMakeFiles/CMakeOutput.log".
See also "/Users/bradjc/temp/libtock-c/openthread-tock/build/CMakeFiles/CMakeError.log".
cp: build/openthread/src/core/libopenthread-mtd.a: No such file or directory
make: *** [all] Error 1
I can't even build with cmake :(
That's strange. Let me look into this....
A couple of updates....
- Following up on the CMake issues, it seems this is an issue on MacOS with the arm-gcc provided. @bradjc was able to fix this locally, but we will need a long term fix before merging this.
- The most recent push brings this branch up to date with the current master branch in Tock. I need to finish going through and incorporating the remainder of the feedback and comments above.
I would like to propose we compile openthread in advance and provide pre-compiled binaries (like we do with newlib/libcpp/picolib). I do not think we can provide a quality user experience with our current build system (and interfacing with openthread's build system) to compile the library at the same time as compiling apps. Thoughts?
I think that is a bad idea. I feel like the xz drama clearly shows why. It's difficult to audit binary blobs that we ship to users.
My preference is to use git submodules here, but I understand your frustrations / concerns @bradjc. In my opinion, the submodule is nice for openthread since the code base will likely not be altered and it serves as an explicit pointer to the detached head at the commit we set in the
libtock-crepo. Additionally, the submodule in my opinion is more explicit for people navigating through the codebase in github as a pointer to the openthread repo.
+1 Submodules are clunky, but they are commonly used and industry standard. As you say it makes it easy to track future changes and does explicitly show we are using the openthread repo and the exact commit.
If the consensus is for using a zip over the submodule, this would not be an issue as we could obtain a zip of the openthread repo. However, I think using an entirely precompiled binary would be a mistake. The biggest downside I see to precompiled binaries surrounds customization of openthread. OpenThread provides a high degree of customizable build flags that can be specified in config header files and also as CMake arguments. Using a precompiled binary pigeonholes us to our specific build configuration for OpenThread. A good example of this is the build flag for logging and whether to compile the Full Thread Device vs Minimal Thread Device.
+1
I would like to propose we compile openthread in advance and provide pre-compiled binaries (like we do with newlib/libcpp/picolib). I do not think we can provide a quality user experience with our current build system (and interfacing with openthread's build system) to compile the library at the same time as compiling apps. Thoughts?
I think that is a bad idea. I feel like the xz drama clearly shows why. It's difficult to audit binary blobs that we ship to users.
It's a very advanced attack, but I doubt the defense is expecting end users to audit source code. I also doubt that debian/ubuntu and every other app store-like environment are going to stop sending compiled binaries to their users. I think we may be able to learn from the xz attack, but I think we have to take on the challenge, not defer to users to audit code.
I maybe should have been more clear.
I don't think everyone is going to switch to Gentoo.
I do think it shines a light on random developers committing non-reproducible binary blobs. I suspect users will start to expect a bit more then "I built this on my random development machine and now you are running it, trust me it's fine, I provided a SHA as proof".
Building something on the Debian infrastructure as part of a reproducible build system and signing it with a Debian trusted key isn't really the same as someone uploading some build artifacts to libtock-c.
I maybe should have been more clear.
I don't think everyone is going to switch to Gentoo.
I do think it shines a light on random developers committing non-reproducible binary blobs. I suspect users will start to expect a bit more then "I built this on my random development machine and now you are running it, trust me it's fine, I provided a SHA as proof".
Building something on the Debian infrastructure as part of a reproducible build system and signing it with a Debian trusted key isn't really the same as someone uploading some build artifacts to libtock-c.
It's not just @lschuermann and I who think this either
It has now alerted the entire Linux community to this new type of attack. We now know that binary blobs even in test-files (which aren't shipped to end users) can still infect a project, if the groundwork has been done in the project's open source release-scripts, such as in this case. Projects can now start demanding that every binary blob added to any project must be reproducible from scratch.
https://www.reddit.com/r/linux/comments/1bvdjgs/xz_shows_our_strength/
Admittedly this packaging discussion has been a bit of a moving target as I've worked hard to figure out what is possible. I now believe we can build openthread with our existing libtock-c build system (branch: https://github.com/tock/libtock-c/compare/master...ot-bradjc), so we do not need to precompile libraries for our supported platforms.
I do ask that going forward we all keep our users, specifically new users in mind. Attacks are shiny, but we can't ignore our user base and what supports them and what ensures they have a good experience using Tock (and for the first time). This necessarily leads to tradeoffs which must be balanced.
Todos:
- Update makefiles and build structure from https://github.com/tock/libtock-c/tree/ot-bradjc
- Need to actually figure out what flags we need set. I included some in the makefile while debugging, which may be redundant or unwanted. Should document which flags we are setting in the makefile(s).
- I had to hack around the cortex-m0 for mbedtls. I tried to make it clear how I modified the header file. I think it should be possible to use #undef and include the version from openthread instead, and then unset the asm flag on thumb1.
- I think we should create a new helper makefile in libtock-c/openthread that apps can include which setup all of the EXTERN_LIBS needed for openthread. This means we don’t have to copy the list to every ot app. We also can’t use the makefile.app because the extern_libs variable is not handled recursively.
- Rename folder to just
openthread(or I supposelibopenthreadwould also be consistent). - Simplify the platform directory, remove empty/unneeded files, remove folder nesting.
- Rename from nrf52840 to tock in the platform library.
Most recent push completes todos 5,6,7.
- [x] Rename folder to just openthread (or I suppose libopenthread would also be consistent).
- [x] Simplify the platform directory, remove empty/unneeded files, remove folder nesting.
- [x] Rename from nrf52840 to tock in the platform library.
Testing https://github.com/tock/libtock-c/tree/ot-bradjc the openthread library compiles using the new build system, but the flashed app does not operate correctly (i.e. unable to join thread network). I'll look more into what is causing this, but we will need to resolve this issue before incorporating the new build system here.
I've updated ot-bradjc with including the correct config file and refactoring how we modify the mbedtls-config.
@bradjc I've merged your changes into my local version of this branch and OpenThread is working properly. I see that some of the ot-bradjc branch changes are to the TockLibrary makefiles. Should I block on pushing a merged version here until we incorporate the Tocklibrary changes into master?
@bradjc I've merged your changes into my local version of this branch and OpenThread is working properly. I see that some of the ot-bradjc branch changes are to the TockLibrary makefiles. Should I block on pushing a merged version here until we incorporate the Tocklibrary changes into master?
Those changes are upstreamed. Just need a rebase.
I merged the changes from the ot-bradjc branch (the non openthread commits from brad should all be already merged into master). As is, this will fail CI since we have a warning for stack-usage being unbounded in libtcplp. I could not find a way to disable this warning.
Edit: It looks like github is detecting these as unique changes... let me rebase.
Ok the last piece on the build side is the controversial #383. That will enable the libraries to automatically compile when trying to compile the app.
@bradjc does the revised libtock build system support this now?
I think we should create a new helper makefile in libtock-c/openthread that apps can include which setup all of the EXTERN_LIBS needed for openthread. This means we don’t have to copy the list to every ot app. We also can’t use the makefile.app because the extern_libs variable is not handled recursively.
@bradjc does the revised libtock build system support this now?
I think we should create a new helper makefile in libtock-c/openthread that apps can include which setup all of the EXTERN_LIBS needed for openthread. This means we don’t have to copy the list to every ot app. We also can’t use the makefile.app because the extern_libs variable is not handled recursively.
It's not really something the build system needs to support, we just need to make the makefile(s).
Update on the state of the PR...
@bradjc I believe I have addressed all outstanding feedback and todos with the exception of:
- timer bug (blocking on https://github.com/tock/tock/pull/3973 and updating openthread logic accordingly)
- eui64 support (#409)
- lqi/rssi (https://github.com/tock/tock/pull/3972)
The alarm.c file in the most recent commit was outdated. Updating now and will push soon.
The most recent commits add the logic needed to resolve the alarm overflow bug leading to the device dropping off the network at 7 minutes on the nordic boards.
This will be blocking on the left padding/left justified alarm capsule PRs. Testing with https://github.com/tock/tock/pull/3973, this bug is now resolved.
TODOs remaining:
- LQI (https://github.com/tock/tock/pull/3972) - will add this to the OpenThread app once this PR is merged.
- EUI64 (https://github.com/tock/libtock-c/pull/409) @bradjc I believe your feedback is addressed, unless I am still missing some details. I will remove the hardcoded values and update accordingly once merged.
- Separate apps as mentioned above.
In regards to separating apps, there are helper functions I defined that will be used across openthread apps. Do we want to place these helper functions in libopenthread as libtock_openthread_*?