Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions board/common/post-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,8 @@ mkuserguide()
if [ "$BR2_PACKAGE_WEBUI" = "y" ]; then
mkuserguide
fi

Comment thread
troglobit marked this conversation as resolved.
# Drop dangling Finit enabled/*.conf symlinks, e.g., optional services
# not part of this image, they cause noise at every initctl reload.
# NOTE: must be the last step before creating the image!
find "$TARGET_DIR/etc/finit.d/enabled" -xtype l -delete 2>/dev/null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed once, not on each build. Increase the build-time unnecessary.

13 changes: 13 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ All notable changes to the project are documented in this file.

- Upgrade Linux kernel to 6.18.44 (LTS)
- Upgrade Buildroot to 2025.02.15 (LTS)
- Upgrade mdns-alias to [v1.3][ma13]: fixes crash on hostname change while
disconnected from Avahi, treats entry group failures and CNAME collisions
as transient (retried instead of exiting), and quieter logs by default
- Add support for firewall address-set (ipset): named sets of IP addresses and
networks, usable as zone sources for per-IP access control, issue #1189
- Build RPi64 SD card images in release builds
- Include .pkg files in release builds
- The `statd` service now logs at `notice` level by default, like other
services, and supports `-v <level>` to adjust verbosity at runtime

### Added

Expand All @@ -24,6 +29,14 @@ All notable changes to the project are documented in this file.

- Fix annoying "cannot deselect all services" or reset to YANG default in the
web interface's firewall configuration page
- Fix sporadic slow response, or timeouts, when reading device status while
mDNS neighbors are being discovered, e.g., after an mDNS restart. Updates
to the neighbor table are now batched, and politely retried when other users
or services keep the system busy, logged as:

statd[3558]: mdns: operational datastore busy, retrying ...

[ma13]: https://github.com/troglobit/mdns-alias/releases/tag/v1.3

[v26.06.0][] - 2026-07-01
-------------------------
Expand Down
2 changes: 1 addition & 1 deletion package/mdns-alias/mdns-alias.hash
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# From GitHub release
sha256 9f194fa0b6e34fd915054394ef5b820a4f6b1755ace5ed1011bfba6df550accf mdns-alias-1.2.tar.gz
sha256 8186f0758f184cbdcab1033e4945117a587356c323e53bcdd19d47911ee2567b mdns-alias-1.3.tar.gz

# Locally generated
sha256 3d6f910b5e198f3daab48047b8ee6949040f7abee3927daf2e231f265faf7d91 LICENSE
2 changes: 1 addition & 1 deletion package/mdns-alias/mdns-alias.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
################################################################################

MDNS_ALIAS_VERSION = 1.2
MDNS_ALIAS_VERSION = 1.3
MDNS_ALIAS_SITE = https://github.com/troglobit/mdns-alias/releases/download/v$(MDNS_ALIAS_VERSION)
MDNS_ALIAS_LICENSE = ISC
MDNS_ALIAS_LICENSE_FILES = LICENSE
Expand Down
7 changes: 7 additions & 0 deletions package/skeleton-init-finit/skeleton-init-finit.mk
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@ endef
SKELETON_INIT_FINIT_POST_INSTALL_TARGET_HOOKS += SKELETON_INIT_FINIT_SET_ULOGD
endif

ifeq ($(BR2_PACKAGE_TTYD),y)
define SKELETON_INIT_FINIT_SET_TTYD
cp $(SKELETON_INIT_FINIT_AVAILABLE)/ttyd.conf $(FINIT_D)/available/
endef
SKELETON_INIT_FINIT_POST_INSTALL_TARGET_HOOKS += SKELETON_INIT_FINIT_SET_TTYD
endif

ifeq ($(BR2_PACKAGE_WATCHDOGD),y)
define SKELETON_INIT_FINIT_SET_WATCHDOGD
cp $(SKELETON_INIT_FINIT_AVAILABLE)/watchdogd.conf $(FINIT_D)/available/
Expand Down
2 changes: 1 addition & 1 deletion package/statd/statd.conf
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#set DEBUG=1
service name:statd [12345] <pid/confd> statd -f -p /run/statd.pid -n -- Status daemon
service name:statd [12345] <pid/confd> statd -- Status daemon
Comment thread
troglobit marked this conversation as resolved.
6 changes: 6 additions & 0 deletions src/confd/src/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ int finit_enable(const char *svc)
(int)(at - svc), svc);
}

if (!fexist(src)) {
/* Optional service not part of this image, avoid dangling symlink */
INFO("%s is not available in this image, cannot enable", svc);
return 0;
}

snprintf(dst, sizeof(dst), FINIT_RCSD "/enabled/%s.conf", svc);
if (symlink(src, dst) && errno != EEXIST) {
ERRNO("failed enabling %s", svc);
Expand Down
7 changes: 4 additions & 3 deletions src/confd/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,10 +655,11 @@ int main(int argc, char **argv)
else if (!strcmp(optarg, "warning"))
log_level = LOG_WARNING;
else if (!strcmp(optarg, "info"))
log_level = LOG_NOTICE;
else if (!strcmp(optarg, "debug"))
log_level = LOG_INFO;
else if (!strcmp(optarg, "debug")) {
log_level = LOG_DEBUG;
else {
debug = 1;
} else {
fprintf(stderr, "confd error: Invalid verbosity \"%s\"\n", optarg);
return EXIT_FAILURE;
}
Expand Down
1 change: 1 addition & 0 deletions src/statd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ACLOCAL_AMFLAGS = -I m4
sbin_PROGRAMS = statd
statd_SOURCES = statd.c shared.c shared.h journal.c journal_retention.c journal.h avahi.c avahi.h
statd_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
statd_CPPFLAGS += -DSTATD_VERSION=\"$(PACKAGE_VERSION)\"
statd_CFLAGS = -W -Wall -Wextra
statd_CFLAGS += $(jansson_CFLAGS) $(libyang_CFLAGS) $(sysrepo_CFLAGS)
statd_CFLAGS += $(libsrx_CFLAGS) $(libite_CFLAGS)
Expand Down
97 changes: 79 additions & 18 deletions src/statd/avahi.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,57 @@ static int sr_setstr(sr_session_ctx_t *ses, const char *xpath, const char *val)
return err;
}

/*
* Resolver events arrive in bursts, e.g., browse storms after an avahi
* restart. Instead of one sr_apply_changes() per event, coalesce all
* edits staged on ctx->sr_ses and apply once the burst settles. On
* datastore contention, back off and retry rather than block -- this
* loop also serves all operational get callbacks.
*/
#define MDNS_APPLY_DEBOUNCE 0.5
#define MDNS_APPLY_TIMEOUT 1000 /* ms */
#define MDNS_APPLY_RETRY_MAX 6 /* caps backoff at 0.5 * 2^6 = 32 s */

static void ds_apply_cb(struct ev_loop *loop, ev_timer *w, int revents)
{
struct mdns_ctx *ctx = (struct mdns_ctx *)
((char *)w - offsetof(struct mdns_ctx, apply_timer));
int err;

(void)loop;
(void)revents;

err = sr_apply_changes(ctx->sr_ses, MDNS_APPLY_TIMEOUT);
switch (err) {
case SR_ERR_OK:
ctx->apply_retries = 0;
break;
case SR_ERR_TIME_OUT:
case SR_ERR_LOCKED:
if (ctx->apply_retries < MDNS_APPLY_RETRY_MAX)
ctx->apply_retries++;
if (ctx->apply_retries == 3)
NOTE("mdns: operational datastore busy, retrying ...");
ev_timer_set(&ctx->apply_timer, MDNS_APPLY_DEBOUNCE * (1 << ctx->apply_retries), 0.0);
ev_timer_start(ctx->loop, &ctx->apply_timer);
break;
default:
ERROR("mdns: sr_apply_changes: %s", sr_strerror(err));
sr_discard_changes(ctx->sr_ses);
ctx->apply_retries = 0;
break;
}
}

static void ds_schedule_apply(struct mdns_ctx *ctx)
{
if (ev_is_active(&ctx->apply_timer))
return;

ev_timer_init(&ctx->apply_timer, ds_apply_cb, MDNS_APPLY_DEBOUNCE, 0.0);
ev_timer_start(ctx->loop, &ctx->apply_timer);
}

/*
* Return an XPath string literal quoting val: single-quoted unless val
* contains a single quote, in which case double quotes are used instead.
Expand Down Expand Up @@ -437,13 +488,12 @@ static void ds_push_resolver(struct mdns_ctx *ctx, struct avahi_service *svc,
}

if (err) {
/* drops any coalesced edits too, later events repopulate */
sr_discard_changes(ctx->sr_ses);
return;
}

err = sr_apply_changes(ctx->sr_ses, 0);
if (err)
ERROR("mdns: sr_apply_changes: %s", sr_strerror(err));
ds_schedule_apply(ctx);
}

static void ds_delete_service(struct mdns_ctx *ctx, const char *hostname, const char *name)
Expand All @@ -470,7 +520,7 @@ static void ds_delete_neighbor(struct mdns_ctx *ctx, const char *hostname)
static void ds_clear_all(struct mdns_ctx *ctx)
{
sr_delete_item(ctx->sr_ses, XPATH_BASE, 0);
sr_apply_changes(ctx->sr_ses, 0);
ds_schedule_apply(ctx);
}

/* --------------------------------------------------------------------------
Expand Down Expand Up @@ -641,7 +691,7 @@ static void service_browser_cb(AvahiServiceBrowser *b,
}
}

sr_apply_changes(ctx->sr_ses, 0);
ds_schedule_apply(ctx);
break;
}

Expand Down Expand Up @@ -788,6 +838,7 @@ static void reconn_cb(struct ev_loop *loop, ev_timer *w, int revents)
* that a normal daemon restart cancels this timer before it fires.
*/
#define MDNS_WARN_DELAY 10.0
#define MDNS_FAIL_ESCALATE 3 /* NOTE level after 3 x MDNS_WARN_DELAY */

static void mdns_retry_cb(struct ev_loop *loop, ev_timer *w, int revents)
{
Expand All @@ -798,8 +849,12 @@ static void mdns_retry_cb(struct ev_loop *loop, ev_timer *w, int revents)
(void)revents;
ctx->fail_count++;

if (mdns_is_enabled(ctx))
WARN("mdns: mDNS daemon not responding, will reconnect automatically");
if (mdns_is_enabled(ctx)) {
if (ctx->fail_count >= MDNS_FAIL_ESCALATE)
NOTE("mdns: mDNS daemon still not responding, will keep trying");
else
INFO("mdns: mDNS daemon not responding, will reconnect automatically");
}
}

static void client_cb(AvahiClient *c, AvahiClientState state, void *userdata)
Expand All @@ -813,7 +868,10 @@ static void client_cb(AvahiClient *c, AvahiClientState state, void *userdata)
if (ctx->fail_count > 0) {
ev_timer_stop(ctx->loop, &ctx->reconn_timer);
ev_timer_stop(ctx->loop, &ctx->retry_timer);
NOTE("mdns: mDNS daemon reconnected");
if (ctx->fail_count >= MDNS_FAIL_ESCALATE)
NOTE("mdns: mDNS daemon reconnected");
else
INFO("mdns: mDNS daemon reconnected");
ctx->fail_count = 0;
}
INFO("mdns: client running");
Expand Down Expand Up @@ -850,16 +908,15 @@ static void client_cb(AvahiClient *c, AvahiClientState state, void *userdata)
ev_timer_start(ctx->loop, &ctx->retry_timer);
}

{
while (!LIST_EMPTY(&ctx->type_entries)) {
struct avahi_type_entry *te;

while (!LIST_EMPTY(&ctx->type_entries)) {
te = LIST_FIRST(&ctx->type_entries);
avahi_service_browser_free(te->browser);
LIST_REMOVE(te, link);
free(te);
}
te = LIST_FIRST(&ctx->type_entries);
avahi_service_browser_free(te->browser);
LIST_REMOVE(te, link);
free(te);
}

if (ctx->type_browser) {
avahi_service_type_browser_free(ctx->type_browser);
ctx->type_browser = NULL;
Expand Down Expand Up @@ -929,11 +986,11 @@ void mdns_ctx_reconnect(struct mdns_ctx *ctx)
int avahi_err;

if (!mdns_is_enabled(ctx)) {
NOTE("mdns: mDNS is disabled, ignoring reconnect request");
INFO("mdns: mDNS is disabled, ignoring reconnect request");
return;
}

NOTE("mdns: reconnecting on request");
INFO("mdns: reconnecting on request");

ev_timer_stop(ctx->loop, &ctx->reconn_timer);
ev_timer_stop(ctx->loop, &ctx->retry_timer);
Expand Down Expand Up @@ -973,6 +1030,8 @@ void mdns_ctx_exit(struct mdns_ctx *ctx)
ev_timer_stop(ctx->loop, &ctx->reconn_timer);
if (ev_is_active(&ctx->retry_timer))
ev_timer_stop(ctx->loop, &ctx->retry_timer);
if (ev_is_active(&ctx->apply_timer))
ev_timer_stop(ctx->loop, &ctx->apply_timer);

/* Free browsers explicitly before freeing the client */
while (!LIST_EMPTY(&ctx->type_entries)) {
Expand All @@ -991,7 +1050,9 @@ void mdns_ctx_exit(struct mdns_ctx *ctx)
}

if (ctx->sr_ses) {
ds_clear_all(ctx);
/* event loop is going away, flush synchronously */
sr_delete_item(ctx->sr_ses, XPATH_BASE, 0);
sr_apply_changes(ctx->sr_ses, MDNS_APPLY_TIMEOUT);
sr_session_stop(ctx->sr_ses);
ctx->sr_ses = NULL;
}
Expand Down
2 changes: 2 additions & 0 deletions src/statd/avahi.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct mdns_ctx {
unsigned int fail_count; /* Non-zero while avahi-daemon is absent */
ev_timer reconn_timer; /* Free+recreate client after brief delay */
ev_timer retry_timer; /* Deferred warn-log timer */
ev_timer apply_timer; /* Debounced DS apply, with retry */
unsigned int apply_retries;
LIST_HEAD(, avahi_neighbor) neighbors;
LIST_HEAD(, avahi_service) services; /* Flat list; keyed by 5-tuple */
LIST_HEAD(, avahi_type_entry) type_entries;
Expand Down
Loading