shared-state-async
https://github.com/libremesh/lime-packages/blob/master/packages/shared-state-asyncReadme
= LibreMesh: Shared State Overview
:toc:
:toclevels: 3== Introduction
LibreMesh is an open-source framework designed to facilitate the creation of community mesh networks. A key component of this framework is the Shared State, a Conflict-Free Replicated Data Type (CRDT) daemon. This module enables seamless information exchange between nodes in a decentralized network, ensuring consistency and reliability.
The official repository is: https://github.com/LibreMesh/shared-state-async.
Features:
Conflict-Free Synchronization: Shared State ensures data consistency across nodes without requiring a central authority or lock mechanism.
Decentralized Communication: Nodes exchange data directly, allowing the network to function even in the absence of a central controller.
Flexible Data Types: Supports various data types, including Wi-Fi link information, node details, and more.
== Available Commands
Shared State provides several commands to interact with and manage data types. Below is an overview of the most commonly used commands for getting and managing data.
shared-state-async Usage: shared-state-async OPERATION [ARGUMENTS] Supported operations: discover, dump, get, insert, peer, register, syncGet
In LibreMesh, shared-state is already included and running so you can run this command. This command allows you to retrieve the current state of a specific data type.
shared-state-async get <data_type>Example:
shared-state-async get net-statsInsert
This command is used to insert data into Shared State. You can specify the data type and the information you want to insert using std input.
echo '{}' | shared-state-async insert <data_type>Example:
echo '{"cheche":{"src_loc":{"long":"-64.4228178","lat":"-31.8019512"},"links":{"ae40411f73a8c64a00fc3abe":{"freq":2462,"iface":"wlan0-mesh","tx_rate":144400,"dst_mac":"c6:4a:00:fc:3a:be","channel":11,"chains":[-40,-35],"signal":-34,"rx_rate":144400,"src_mac":"ae:40:41:1f:73:a8"}}}}'| shared-state-async insert wifi_links_info_refDump
Is like get but with extended shared state debug info of a datatype. It will report "Author" and "Ttl"
shared-state-async dump <data_type>Example:
shared-state-async get bat-hosts { ... "ae:40:41:22:55:78": "estela_y_julio_wlan1_mesh_17", "ae:40:41:22:55:7b": "estela_y_julio_wlan2_mesh" } shared-state-async dump bat-hosts ... { "key": "ae:40:41:22:55:78", "value": { "mAuthor": "estela-y-julio", "mTtl": { "xint64": 1422, "xstr64": "1422" }, "mData": "estela_y_julio_wlan1_mesh_17" } }, { "key": "ae:40:41:22:55:7b", "value": { "mAuthor": "estela-y-julio", "mTtl": { "xint64": 1422, "xstr64": "1422" }, "mData": "estela_y_julio_wlan2_mesh" } } ...sync
This is used to force synchronization between nodes. It will try to sync with neighbors but you can also specify a specific host to try to sync to.
In order to get the most accurate and fresh info from a node you must force the publisher of the data type to be executed and then sync your info with that node.Example:
shared-state-async sync bat-hots 8.8.8.8peer
Shared state is basically only one binary that has to be called first with the "peer" argument in order to lunch the daemon. Then the same binary can be used as a tool to interact with the daemon.
shared-state-async peerdiscover
Discover the nodes able to parte in the Shared State network.
shared-state-async discoverregister
Register a new data type or node in the Shared State system.
shared-state-async register DATA-TYPE TYPE-SCOPE UPDATE-INTERVAL BLEACH-TTL== Ubus Wrapper
Shared State also supports using ubus for remote procedure calls (RPC) to interact with the system. Get method returns shared-state "get" json data or reported error in case no json is found. Errors are bubbled up as they come from shared-state inside a json structure with the name "error".
Available commands are:
{ "sync": { "data_type": "str", "peers_ip": "str" }, "get": { "data_type": "str" }, "publish": { "data_type": "str" }, "publish_all": { }, "insert": { "data_type": "str", "json": "str" } }
=== Get
Get bat-hosts
# ubus -S call shared-state-async get "{'data_type': 'bat-hosts'}" {"a8:40:41:1f:73:ab":"lrsegundo_eth1_2","02:95:39:1f:73:aa":"lrsegundo_eth0_250","a8:40:41:1c:85:c3":"lrsegundo_wlan2_mesh","a8:40:41:1c:85:16":"lrsegundo_wlan1_mesh","02:bb:ed:1f:73:aa":"lrsegundo_eth1_250","a8:40:41:1f:73:a8":"lrsegundo_wlan0_ap","aa:40:41:1f:73:a8":"lrsegundo_wlan0_apname","02:db:d6:1f:73:aa":"lrsegundo_eth0_1_250","02:29:0f:1f:73:aa":"lrsegundo_eth1_2_250","c2:10:20:5e:7f:b3":"lrsegundo_bat0","a8:40:41:1f:73:aa":"lrsegundo_eth0"}Get an invalid data type
# ubus -S call shared-state-async get "{'data_type': 'bat-hosss'}" {"error":53248}=== Sync
Sync valid data type# ubus -S call shared-state-async sync "{'data_type': 'bat-hosts'}" {"error":0}Sync invalid data type
ubus -S call shared-state-async sync "{'data_type': 'bat-hoss' }" {"error":53248}Sync valid data type with unreachable ipv4 addresses
# ubus -S call shared-state-async sync "{'data_type': 'bat-hosts' ,'peers_ip':['10.0.0.1','10.0.0.2']}'" {"error":32768}Sync valid data type with invalid ipv4 address
# ubus -S call shared-state-async sync "{'data_type': 'bat-hosts' ,'peers_ip':['10.0.0.1','10.0.2']}'" {"error":61952}Sync invalid data type with specified ipv4 address
ubus -S call shared-state-async sync "{'data_type': 'bat-hosts' ,'peers_ip':['127.0.0.1','127.0.0.1']}'" {"error":53248}Sync valid data type with reachable ipv4 addresses
# ubus -S call shared-state-async sync "{'data_type': 'bat-hosts' ,'peers_ip':['127.0.0.1','127.0.0.1']}'" {"error":0}== Data types
Each data type in Shared State consists of at least two key components:
Definition: Specifies the structure and properties of the data type.
Publisher: Responsible for generating and updating the data.
Hook(optional): optionally a data type can implement a third component that is a hook. These executes custom actions when the data type is updated or accessed.
all data types are in a separate package in LibreMesh and are named "shared-state-dataType". A good example of a package is bat-hosts
=== Available data types
Shared State uses data types to support various functions. Each data types is responsible for handling a specific information, ensuring seamless integration and management of that data within the mesh network.
The some of the currently supported data types include:
bat-hosts: Handles information about hosts in the network and helps resolving node’s domain name.
wifi_links_info: Handles information about Wi-Fi link status and metrics.
node_info: Manages metadata about individual nodes.
babel_links_info: babel routing protocol-specific link data.
bat_links_info: Manages link information for BATMAN-adv networks.
Reference State: One application of Shared State is maintaining a reference state for troubleshooting, diagnostics, and disaster recovery in mesh networks. Refer to the detailed documentation in README.md for more on Reference State.
=== Data types registration
To add support for a new data type, you can develop a custom new data type tailored to your requirements. Data types must be registered into shared-state-async by using a config file. UCI infrastructure is preferred and here is a sample
mSc="plugin_name" uci set shared-state.${mSc}=dataType uci set shared-state.${mSc}.name='data_type_name' uci set shared-state.${mSc}.scope='community' uci set shared-state.${mSc}.ttl='1200' uci set shared-state.${mSc}.update_interval='120' uci commit shared-state
'name' and 'ttl' are the most important attributes.'name' is the name of the data type and 'ttl' parameter stands for "time to live" and will decrease every second until 0.
=== Datatype publishers
In Shared State, publishers are responsible for producing and updating data. Each publisher acts as a source for specific data types, feeding information into the system that is then distributed and replicated across the network.
Publishers must be located at /usr/share/shared-state/publishers
All Publishers will be called periodically using shared-state-async-publish-all, this can also be invoked manually.Sync is called automatically by shared-state daemon every 15s
"ttl" parameter stands for "time to live" and will decrease every second until 0.
Data contents will be erased if "ttl" reaches 0. So calling publishers has to be done periodically before that happens.=== Datatype hooks
Datatype hooks allow custom behavior to be triggered when specific data types are updated or accessed. These hooks enable developers to extend the functionality of Shared State by defining actions that respond to changes in the data.
Examples of hooks in action can be found in the
shared-state-mesh-upgrade
package. This package demonstrates how hooks can be utilized to enhance mesh network functionalities.=== Adding Hooks
Hooks can be added by defining callback script tied to specific data types.
hooks scripts must be placed in /usr/share/shared-state/hooks/dataType folder and must read std input as
local indata = io.stdin:read("*all") utils.printJson(JSON.parse(indata))
== Debugging
By default shared state async is already installed in LibreMesh, but if you want to debug you can compile the binary with debug flag enabled.
First you must have a clone of openWRT with LibreMesh feeds installed. Please refer to LibreMesh docs to achieve this.Build with debugging enabledmake package/feeds/libremesh/shared-state-async/clean package/feeds/libremesh/shared-state-async/compile -j$(nproc) CONFIG_DEBUG=yCopy on verde e bluscp -O bin/packages/mips_24kc/libremesh/shared-state-async_*.ipk root@[fe80::ea94:f6ff:fe68:3364%usbe1]:/tmp/ scp -O bin/packages/mips_24kc/libremesh/shared-state-async_*.ipk root@[fe80::6670:2ff:fede:c51e%usbe1]:/tmp/Installopkg install --force-reinstall /tmp/shared-state-async_*.ipkRun with gdbgdbserver :9000 shared-state-asyncAttach with remote OpenWrt gdbscripts/remote-gdb [fe80::ea94:f6ff:fe68:3364%usbe0]:9000 ./build_dir/target-mips_24kc_musl/shared-state-async-*/shared-state-async scripts/remote-gdb [fe80::6670:2ff:fede:c51e%usbe0]:9000 ./build_dir/target-mips_24kc_musl/shared-state-async-*/shared-state-async break shared-state-async.cc:55 run listen run sync bat-hosts fe80::ea94:f6ff:fe68:3364%br-lan run sync bat-hosts fe80::d237:45ff:fefc:3cdd%br-lanStressing the serverwhile Builds/build-lime-shared-state-async-node-Desktop-Debug/shared-state-async sync bat-hosts fe80::ea94:f6ff:fe68:3364%usbeth0; do echo ------------------------------------------------------------------- ;done while shared-state-async sync bat-hosts fe80::ea94:f6ff:fe68:3364%br-lan; do echo ------------------------------------------------------------------- ;done=== Interesting Readings
VoCore2: Develop for OpenWrt on Qt Creator
https://vonger.cn/?p=14657== Contributing
We welcome contributions to improve Shared State and its applications. Feel free to open issues or submit pull requests on the [GitHub repository](https://github.com/LibreMesh/lime-packages)
Makefile
# Shared State
#
# Copyright (C) 2023-2024 Gioacchino Mazzurco <gio@eigenlab.org>
# Copyright (c) 2023 Javier Jorge <jjorge@inti.gob.ar>
# Copyright (c) 2023 Instituto Nacional de Tecnología Industrial
# Copyright (C) 2023-2024 Asociación Civil Altermundi <info@altermundi.net>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>
#
# SPDX-License-Identifier: AGPL-3.0-only
include $(TOPDIR)/rules.mk
GIT_COMMIT_DATE:=$(shell git log -n 1 --pretty=%ad --date=short . )
GIT_COMMIT_TSTAMP:=$(shell git log -n 1 --pretty=%at . )
PKG_NAME:=shared-state-async
PKG_VERSION=$(GIT_COMMIT_DATE)-$(GIT_COMMIT_TSTAMP)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/libremesh/shared-state-async.git
PKG_SOURCE_VERSION:=db58e3d16e8658417956f9bb42e7e87f6aadcd4d
PKG_MAINTAINER:=Asociación Civil Altermundi <info@altermundi.net>
PKG_LICENSE:=AGPL-3.0
HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/$(PKG_NAME)
TITLE:=shared-state C++ async re-implementation
CATEGORY:=LibreMesh
# TODO: Statically linking libstdcpp instead of depending on it and then
# stripping unused symbols might reduce space usage, until this is the
# only package to use it
DEPENDS:=+libstdcpp
endef
define Package/$(PKG_NAME)/description
shared-state re-written in C++20 and corotuines to handle information exchange between network nodes more efficiently.
endef
# Otherwise OpenWrt's CPPFLAGS are ignored
TARGET_CFLAGS += $(TARGET_CPPFLAGS)
CMAKE_OPTIONS += -DCMAKE_VERBOSE_MAKEFILE=ON
# Disable Cpptrace as it depends on zlib and doesn't seems to work anyway on
# OpenWrt even with CONFIG_DEBUG=y it prints out
# Stack trace (most recent call first):
# #0 0x00000000
# #1 0x00000000
# #2 0x00000000
CMAKE_OPTIONS += -DSS_CPPTRACE_STACKTRACE=OFF
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/shared-state-async $(1)/usr/bin/
$(CP) ./files/* $(1)/
# TODO: Remove this line once discovery is reimplemented in C++
$(CP) ../shared-state/files/usr/bin/shared-state-get_candidates_neigh $(1)/usr/bin/shared-state-async-discover
endef
$(eval $(call BuildPackage,$(PKG_NAME)))