Sys Runtime Configuration Registry#19895
Conversation
|
thanks for this very careful PR description, including the feature matrix comparison! |
There was a problem hiding this comment.
Sorry for not having got any feedback on this so far.
Based on the metrics only, I doubt this has a chance to get merged. The amount of lines of codes IMO is way too large to justify adding it.
Pro arguments of merging this
- lots of cool features
Contra arguments of merging this
- maintaining 11K loc is a huge effort
- 11K loc translate into huge growth of
.text, making it difficult to actually use on MCUs with highly constrained memory - the typical use cases likely can be addressed well with the EEPROM registry that is already upstream, the FlashDB package that is already upstream, and the file systems that are already upstream
I'm aware that this is an a****e move from me to NACK this without having looked at the code. I'm pretty sure that most if not all of the other maintainers feel similar and didn't start to look into the code based on the metrics. And I think it is better to have frustrating feedback than having this lingering here and being ignored.
Thanks for your reply, conveying your concerns regarding the size of this PR. I want to do some clarification regarding the actual code size of this PR. -- In-Fact most of my code lies in We could discuss removing this feature. It should default to be turned off at the moment anyways since I would argue, that very constrained devices don't want to waste processing time on these checks. Okay to give more insight here is a list of the different modules of my implementation and their sizes: Core + Extension modules
Configuration Schemas (Code-Generated)Configuration Schemas are generated by a python script and usually only the schema that is used will be compiled.
Storage Implementations
Applications
Tests
|
|
From my perspective the lines of code are much less relevant compared to the added ROM requirements. Well, yes, this is an optional feature, but it still doesn't do any good when people can't use it in the majority of the cases because ROM would overflow. I only did a very quick test comparing the provided registry example application with a similar application without it: the difference (on nrf52) was ~60k vs ~22k of ROM - that's indeed huge. However, of course this comparison is not quite fair and very superficial. Do you have more elaborated data on how big the actual overhead compared to alternate solutions would be? |
|
I will do more detailed measurements on the ROM overhead in the coming weeks. It should be considered that the current example also has a dependency on lifflefs, VFS etc. Which is not necessarily a requirement for the persistent storage. So more insight is necessary when comparing the ROM overhead of the different parts of the registry. |
|
Hey, sorry for the reactions being so negative. The problem with the config system is that everybody wants to have a config system for their subsystem, we can expect that a config system will be part of most firmwares in the future, so it's overhead can not be too big. I understand that this PR includes all possible and optional features, but to better reason about the solution, can you provide a minimal viable config system core that just includes the basic functionality (without any optional dependencies). We should also understand that we might to reach the perfect solution on the fist try, but if the API is sane we can always improve the implementation later on. |
Yeah no worries that is already on my list for early January, sorry that I haven't really found time to provide the more detailed measurements yet, it became a bit more busy for me towards the end of the year and Christmas :) I think there is a need for me to provide better explanations of what each extension is used for and what their costs are. I was planning to make a small user story for a minimal registry that for example gives some basic ability to manage the on board LED. Anyways thank you for your feedback, it is very much appreciated by me :) |
|
Alternatively you could also see if #19557 covers your use case and if not, what's lacking - @fabian18 is getting paid to work on this and will likely maintain it for the years to come, so without having looked into either PR extensively, that would me more inclined towards his solution. |
to not lose track of ongoing discussions elsewhere: https://forum.riot-os.org/t/runtime-configuration-breakout-session/4006 |
|
So I have added a minimal example application under As this is the minimal example, it should be noted that it does Running (I have chosen the same BOARD as Fabian for better comparison) What can this minimal example do?The minimal example includes enough capabilities of the What can't this minimal example do?The minimal example can not integrate with dynamic |
MichelRottleuthner
left a comment
There was a problem hiding this comment.
Wooha many files. Thanks for the contribution and providing additional data 👍
First round of review below.
maribu
left a comment
There was a problem hiding this comment.
Thanks for updating the PR and providing the metrics.
I see that the LoC have now gone down to 7K. This is still rather large for reviewing. Would it be possible if you split out a PR that does not provide any storage backend yet? E.g. just the base features + test + an example that uses the shell interface, no persistence yet?
I added some nitpicks inline.
6102a76 to
b9382b5
Compare
2bc9b35 to
e978d26
Compare
|
I close this, as the plan is to continue this in smaller reviewable pull requests. The first one is: #22092 After that one got merged, I will rebase this PR to keep a single place with everything working and then create more split-out PRs based on this one. |
In that case I'd rather leave it open as draft PR :) |
Thank you, that is also fine :) |
|
Superseded by #22092. |

RIOT Runtime Configuration Registry
This is a continuation of the effort previously done in #10622, but its architecture has dramatically changed since then.
Abstract
This PR implements a system level runtime configuration system for RIOT.
A runtime configuration system is in charge of providing a mechanism to set and get the values of
Configuration Parametersthat are used during the execution of the firmware, as well as a way to persist these values. Runtime configurations are deployment-specific and can be changed on a per node basis.Appropriate management tools could also enable the configuration of nodes.
Examples of runtime configurations are:
These parameters might have constraints, like a specific order to be applied (due to interdependencies) or value boundaries.
The main advantages of having such a system are:
Modules
The RIOT Registry consists of various modules that are not all needed for minimal operation:
registryCore functionality such as set, get, export and apply operations to retrieve and set configurations.
registry_storageAdds capability to safe parameters to non-volatile storage devices.
registry_int_pathAllows accessing configuration parameters via a path of integers.
registry_string_pathAllows accessing configuration parameters via a path of strings.
registry_cliAllows accessing configuration parameters via a shell command.
Design
Architecture
The proposed architecture, as shown below, is formed by one or more Applications or Configuration Managers and the RIOT Registry.
The RIOT Registry acts as a common interface to access Runtime Configurations and store them in non-volatile storage.
All runtime configurations can be accessed either from the RIOT application using the provided RIOT Registry interfaces or through the interfaces exposed by the Configuration Managers.
A RIOT Application may interact with a Configuration Manager in order to modify access control rules or enable different exposed interfaces.
Path Based Configuration Managers (Needs
int_path or string_pathextension)These Configuration Managers are a simple representation of the default configuration structure of the RIOT Registry.
They use either the
int_pathor thestring_pathRegistry extension module to expose the parameters using a path.Custom Schema Based Configuration Managers
These Configuration Managers have their own configuration structure (custom predefined object models etc.) and can not automatically be mapped to / from the RIOT Registry itself.
To make them work, a custom mapping module needs to be implemented, which maps each Configuration Parameter from the registry to the correct format of the Configuration Manager.
Namespaces and Storages
The RIOT Registry interacts with RIOT modules via
Configuration Schemas, and with non-volatile storages viaStorages.This way the functionality of the RIOT Registry is independent of the functionality of a
moduleorstorageimplementation.It is possible to get or set the values of
Configuration Parameters.It is also possible to transactionally apply configurations or export their values to a buffer or print them.
To persist Configuration Values, it is possible to store them in non-volatile storages.
Any mechanism of security (
access control,encryptionof configurations) isnotdirectly in the scope of the Registry but in the Configuration Managers and the specific implementations of theConfiguration SchemasandStorages.The graphic below shows an example of two
Configuration Namespaces(SYS and APP).The
APPnamespace contains a application specificMy appConfiguration Schema and theSYSnamespace specifies aWLANand aLED StripConfiguration Schema.The application
My appuses the customMy appConfiguration Schema to expose custom Configuration Parameters to the RIOT Registry and the driversWS2812,SK6812andUCS1903contain instances ofthe
LED StripConfiguration Schema to expose common LED Strip Configuration Parameters.Also, there are two Storages available:
MTDandVFS.The
MTDStorage internally uses the RIOTMTDdriver and theVFSStorage internally uses the RIOTVFSmodule.Components
The RIOT Registry is split into multiple components as can be seen in the graphic below:
Registry Core
This component holds the most basic functionality of the RIOT Registry.
It allows to
setandgetConfiguration Values, transactionallyapplythem to make the changes come into effect andexportall Configuration Parameters that exist in a givenConfiguration Namespace,Configuration SchemaorConfiguration Group.Furthermore it is possible to
addConfiguration NamespacesorConfiguration Schema Instances.Registry Namespace
The
Configuration Namespacessuch asSYSorAPPand their respectiveConfiguration Schemasare not part of the Registry itself.It is possible to
addcustomConfiguration Namespacesdepending on the given needs.Storage
The
Storagecomponent provides an interface toloadConfiguration Values from a persistentStorageimplementation or tosavethe current Registry configuration to it.Registry Storage [Extension]
The implementations of a Storage such as
VFSorMTDare not part of the Registry itself and can be switched out with implementations that are most suitable to the given needs.Integer Path [Extension]
The
int_pathcomponent provides helper functions that convert a path of up to 4 integer values to the respective pointer of aConfiguration Namespace,Configuration Schema,Configuration Schema Instance,Configuration GrouporConfiguration Parameterand the other way around.The structure of an integer configuration path is the following:
namespace_id/schema_id/instance_id/group_id | parameter_idFor example:
String Path [Extension]
The
string_pathcomponent provies helper functions that convert a string path to the respective pointer of aConfiguration Namespace,Configuration Schema,Configuration Schema Instance,Configuration GrouporConfiguration Parameterand the other way around.The structure of a string configuration path is the following:
namespace_name/schema_name/instance_id(/group_name)* /parameter_name.The amount of path items is flexible, so the path could only consist of the
namespace_nameor only thenamespace_nameand theschema_nameand so on.For example:\
API
The graphic below shows the API of the RIOT Registry.
The top shows the Core API to manage Configuration Parameters.
On the right-hand side are functions to
setandgetConfiguration Parameters, transactionallyapplythem andexportthem to a buffer or terminal.On the left-hand side are setup functions to
addConfiguration NamespacesandConfiguration Schema Instancesto the Registry.The bottom shows the storage API to manage the persistance of Configuration Parameters.
The left-hand side shows functions to
load”andsaveConfiguration Parameters to and from the persistent Storage.The right-hand side shows functions to
addStorage Sources(for reading) and tosetaStorage Destination(for writing).The Registry can have multiple
Storage Sources, but always only oneStorage Destination.This allows to migrate from an old
Storageto a new one.The functionality of these functions is explained in the following paragraphs.
Core API
Get
A Configuration Value can be retrieved using the
registry_getfunction.The function takes the
registry_node_tand aregistry_value_tpointer (to return the value) as its arguments.Set
A Configuration Value can be set using the
registry_setfunction.The function takes the
registry_node_t, avoid*buffer and the buffer size as its arguments.The buffer must contain the value in its correct c-type.
If the Registry expects a
u8, but au16is provided, the operation will fail.Furthermore the registry can specify constraints like
minimumandmaximumvalues and an array ofallowedorforbiddenvalues.If these constraints are not fulfilled, then the operation will fail as well.
Apply
Once the value(s) of one or multiple
Configuration Parameter(s)are changed by theregistry_setfunction, they still need to be applied, so that the new values are taken into effect.Configuration Parameter(s) can be applied using the
registry_applyfunction.In this case the Registry provides multiple apply functions to allow applying in varying degrees.
The provided functions are
registry_apply, this function applies everyConfiguration Parametercurrently available in the Registry within the specified scope, specified by theregistry_node_targument.When a whole
Schema Instance, or a singleConfiguration Parameteris applied, it will be passed on to theapply_cbhandler of theConfiguration Schema Instance, provided by the module that needs runtime configuration.This way the module gets notified, when the
Configuration Parameterhas been applied and can apply the changes accordingly.Export
Some times it is convenient to have a way to see what
Configuration Namespaces,Configuration Schemas,Configuration Schema Instances,Configuration GroupsorConfiguration Parametersare available within our current RIOT Registry deployment.To get this information there is the
registry_exportfunction.This function exports every
Configuration Objectcurrently available in the Registry within the scope of the providedregistry_node_targument.When a node in the schema is exported, it will be passed on to the
export_cbhandler provided as an argument of eachregistry_export*function.Add Namespaces to the Registry
To be able to use
Configuration Schemasand theirParametersetc. it is necessary to add aConfiguration Namespacethat holds the requiredConfiguration Schemasto the Registry.This is possible using the
REGISTRY_ADD_NAMESPACEmacro, providing the name of theConfiguration Namespaceand a pointer to aregistry_namespace_tobject as arguments.Add Configuration Schema Instances to the Registry
To implement runtime configuration functionality into a module, it is necessary to add a
Configuration Schema Instanceof the neededConfiguration Schemato the Registry.This is possible using the
registry_add_schema_instancefunction, providing theConfiguration Schemaand theConfiguration Schema Instanceas arguments.Storage API (Extension)
Load from Storage
It is often needed to load Configuration Parameters from a non-volatile
Storagedevice.For example when a device restarts after a shutdown.
This is possible using the
registry_storage_loadfunction.This function takes a
registry_storage_instance_tas its arguments.The
the registry_storage_instance_tcontains data such as the mount point.Internally the
Storage Instancesearches its persistent storage device forConfiguration Values.If a
Configuration Valueis found, theStorage Sourcecalls theregistry_setfunction and provides the necessary arguments.Save to Storage
To save
Configuration Valuesto a non-volatileStoragedevice, the Registry provides theregistry_storage_savefunction.This function saves all available
Configuration Parameterswithin the scope specified by theregistry_storage_node_targument.Internally these functions call the
savehandler of the providedStorage Instancefor eachConfiguration Parameterthat has to be saved to storage.The
savehandler of theStorage, of the providedStorage Instancetakes aStorage Instanceproviding data such as the mount point, aregistry_node_t, which describes the location inside the configuration tree and aConfiguration Valueas its arguments.These values provide the needed information to load them back into the registry.
The way how the
Storagestores these values internally is not specified.Set Storage Instances
To be able to expose storage instances to configuration managers such as the RIOT CLI, we have a function called
registry_storage_set_instances, which lets you provide an array of storage instances.Get Storage Destination
To be able to retrieve a list of existing storage instances, we have a function called
registry_storage_get_instances, which takes a pointer to an array ofstorage_instance_tstructs as an output parameter.Comparison to Apache Mynewt Config
While originally our work on the RIOT Registry was heavily inspired by Apache Mynewt Config, it has since evolved to provide features such as
Type Safety, makeString Pathsoptional, introduceInteger Pathsand provide a more modularPointer-Based API.The table below shows the difference between Apache Mynewt Config and the proposed RIOT Registry.
The Idea here is
notto talk down Apache Mynewt Config, as its simplicity of course has its own advantages, but to point out more clearly how our solution differs to it.External Configuration Managers
CLI
The only available Configuration Manager in this PR is a CLI.
It can be tried in the example under
examples/registry.The CLI uses int paths separated by
/.E.g.:
0/0/0/0.CoAP API
The idea is to use the
registry_intand/orregistry_pathmodule to provide a simple CoAP API./getendpointThe get function could be mapped to the CoAP GET function.
/setendpointThe set function could be mapped to the CoAP PUT function.
/applyendpointThis is more tricky.
Possible solutions could be to provide an
/applysuffix or prefix at the end or beginning of a path, to tell the registry, that this is an apply operation./exportendpointThe export function could be implemented using a CoAP GET function using
/exportas a suffix or prefix of the path.CoAP would then return one response containing all the requested objects for example structured using CBOR.
LwM2M
A LwM2M integration would require to write a mapping between each LwM2M Object to the respective RIOT Registry Configuration Schemas.
In this case every LwM2M set operation would immediately trigger a
registry_applyas LwM2M does not provide anapplyoperation.This is not a drawback, as LwM2M allows to set multiple values at the same time, thus covering the same use-case as the
registry_applyfunction.Testing procedure
Testing commands unter tests/unittests:
Issues/PRs references
See also #10622
See also #19557