diff --git a/board/common/rootfs/etc/netd/conf.d/.empty b/board/common/rootfs/etc/netd/conf.d/.empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/board/common/rootfs/usr/share/udhcpc/default.script b/board/common/rootfs/usr/share/udhcpc/default.script index c2a8c24a4..a28eb28fa 100755 --- a/board/common/rootfs/usr/share/udhcpc/default.script +++ b/board/common/rootfs/usr/share/udhcpc/default.script @@ -7,7 +7,7 @@ ACTION="$1" IP_CACHE="/var/lib/misc/${interface}.cache" RESOLV_CONF="/run/resolvconf/interfaces/${interface}.conf" NTPFILE="/run/chrony/dhcp-sources.d/${interface}.sources" -NAME="/etc/netd/conf.d/${interface}-dhcp.conf" +NAME="/etc/net.d/${interface}-dhcp.conf" NEXT="${NAME}+" [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" @@ -118,8 +118,6 @@ set_dhcp_routes() # Reduce changes needed by comparing with previous route(s) cmp -s "$NAME" "$NEXT" && return mv "$NEXT" "$NAME" - - initctl reload netd } clr_dhcp_routes() @@ -127,8 +125,6 @@ clr_dhcp_routes() log "deleting DHCP routes" [ -f "$NAME" ] || return rm "$NAME" - - initctl reload netd } clr_dhcp_addresses() diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 8fd5df4e8..b0c536a50 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -3,7 +3,7 @@ Change Log All notable changes to the project are documented in this file. -[v26.02.1][] - 2026-03-11 +[v26.02.1][] - 2026-03-12 ------------------------- ### Changes @@ -17,6 +17,7 @@ All notable changes to the project are documented in this file. - Fix #1389: legacy name limit in firewalld triggered problems with policy names - Fix #1416: `show firewall` command show an error when the firewall is disabled +- Fix #1438: default route from DHCP client not set at boot, regression in v26.02.0 - Fix instabilities in Zebra route manager after Frr upgrade in v26.02.0 - Fix regression in MVEBU SafeXcel Crypto Engine for Marvell Armada SOCs (37xx, 7k, 8k, and CN913x series). Firmware package lost in v26.01.0 diff --git a/package/netd/Config.in b/package/netd/Config.in index 94bd4a923..96be1fc32 100644 --- a/package/netd/Config.in +++ b/package/netd/Config.in @@ -2,9 +2,10 @@ config BR2_PACKAGE_NETD bool "netd" select BR2_PACKAGE_LIBITE select BR2_PACKAGE_LIBCONFUSE + select BR2_PACKAGE_LIBEV help Network route daemon. Manages static routes and RIP routing. - Reads configuration from /etc/netd/conf.d/*.conf. + Reads configuration from /etc/net.d/*.conf. With FRR: Full routing via gRPC, vtysh, or frr.conf. Without FRR: Standalone Linux backend via rtnetlink. diff --git a/package/netd/netd.mk b/package/netd/netd.mk index 60ab45354..8a658af0f 100644 --- a/package/netd/netd.mk +++ b/package/netd/netd.mk @@ -4,13 +4,13 @@ # ################################################################################ -NETD_VERSION = 1.0 +NETD_VERSION = 1.1.0 NETD_SITE_METHOD = local NETD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/netd NETD_LICENSE = BSD-3-Clause NETD_LICENSE_FILES = LICENSE NETD_REDISTRIBUTE = NO -NETD_DEPENDENCIES = libite libconfuse jansson +NETD_DEPENDENCIES = libite libconfuse jansson libev NETD_AUTORECONF = YES NETD_CONF_ENV = CFLAGS="$(INFIX_CFLAGS)" diff --git a/src/confd/src/routing.c b/src/confd/src/routing.c index 5bb8b45af..1ef2a5f9e 100644 --- a/src/confd/src/routing.c +++ b/src/confd/src/routing.c @@ -8,7 +8,7 @@ #define XPATH_BASE_ "/ietf-routing:routing/control-plane-protocols/control-plane-protocol" #define XPATH_OSPF_ XPATH_BASE_ "/ietf-ospf:ospf" -#define NETD_CONF "/etc/netd/conf.d/confd.conf" +#define NETD_CONF "/etc/net.d/confd.conf" #define NETD_CONF_NEXT NETD_CONF "+" #define NETD_CONF_PREV NETD_CONF "-" #define OSPFD_CONF "/etc/frr/ospfd.conf" diff --git a/src/netd/Makefile.am b/src/netd/Makefile.am index 16803eac6..0de3ad9e0 100644 --- a/src/netd/Makefile.am +++ b/src/netd/Makefile.am @@ -6,7 +6,7 @@ netd_SOURCES = src/netd.c src/netd.h src/config.c src/config.h netd_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE -I$(srcdir)/src netd_CFLAGS = -W -Wall -Wextra netd_CFLAGS += $(libite_CFLAGS) $(libconfuse_CFLAGS) $(jansson_CFLAGS) -netd_LDADD = $(libite_LIBS) $(libconfuse_LIBS) $(jansson_LIBS) +netd_LDADD = $(libite_LIBS) $(libconfuse_LIBS) $(jansson_LIBS) $(EV_LIBS) # Backend selection: FRR gRPC, FRR frr.conf, or Linux kernel if HAVE_FRR_GRPC diff --git a/src/netd/README.md b/src/netd/README.md index 5ebcfc804..aa0aca358 100644 --- a/src/netd/README.md +++ b/src/netd/README.md @@ -60,7 +60,7 @@ make install netd uses [libconfuse](https://github.com/martinh/libconfuse) for configuration parsing, providing a clean and structured format. -Configuration files are placed in `/etc/netd/conf.d/` with the `.conf` extension. Files are processed in alphabetical order. +Configuration files are placed in `/etc/net.d/` with the `.conf` extension. Files are processed in alphabetical order. ### Configuration Format @@ -219,10 +219,10 @@ rip { ### Configuration Files -Configuration files must be placed in `/etc/netd/conf.d/` with the `.conf` extension: +Configuration files must be placed in `/etc/net.d/` with the `.conf` extension: ```bash -/etc/netd/conf.d/ +/etc/net.d/ ├── 10-static.conf # Static routes ├── 20-rip.conf # RIP configuration └── 99-local.conf # Local overrides @@ -256,7 +256,7 @@ netd validates configuration on reload. Check syslog for errors. ``` ┌─────────┐ -│ confd │ Writes /etc/netd/conf.d/confd.conf +│ confd │ Writes /etc/net.d/confd.conf └────┬────┘ │ SIGHUP ▼ diff --git a/src/netd/configure.ac b/src/netd/configure.ac index ca2fd2b19..04b7fa7a1 100644 --- a/src/netd/configure.ac +++ b/src/netd/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.61) -AC_INIT([netd], [1.0.0], [https://github.com/kernelkit/infix/issues]) +AC_INIT([netd], [1.1.0], [https://github.com/kernelkit/infix/issues]) AM_INIT_AUTOMAKE(1.11 foreign subdir-objects) AM_SILENT_RULES(yes) @@ -81,6 +81,16 @@ PKG_CHECK_MODULES([libite], [libite >= 2.6.1]) PKG_CHECK_MODULES([libconfuse], [libconfuse >= 3.0]) PKG_CHECK_MODULES([jansson], [jansson >= 2.0]) +AC_CHECK_HEADER([ev.h], + [saved_LIBS="$LIBS" + AC_CHECK_LIB([ev], [ev_loop_new], + [EV_LIBS="-lev"], + [AC_MSG_ERROR("libev not found")]) + LIBS="$saved_LIBS"], + [AC_MSG_ERROR("ev.h not found")] +) +AC_SUBST([EV_LIBS]) + test "x$prefix" = xNONE && prefix=$ac_default_prefix test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' diff --git a/src/netd/src/netd.c b/src/netd/src/netd.c index 3d120f1f4..c8f183c16 100644 --- a/src/netd/src/netd.c +++ b/src/netd/src/netd.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include "netd.h" @@ -9,9 +11,6 @@ int debug; -static sig_atomic_t do_reload; -static sig_atomic_t do_shutdown; - static struct route_head active_routes = TAILQ_HEAD_INITIALIZER(active_routes); static struct rip_config active_rip; @@ -46,19 +45,7 @@ static int backend_apply(struct route_head *routes, struct rip_config *rip) { } #endif -static void sighup_handler(int sig) -{ - (void)sig; - - INFO("Got SIGHUP, reloading ..."); - do_reload = 1; -} - -static void sigterm_handler(int sig) -{ - (void)sig; - do_shutdown = 1; -} +static ev_timer retry_w; static void route_list_free(struct route_head *head) { @@ -118,7 +105,7 @@ static void rip_config_free(struct rip_config *cfg) } } -static void reload(void) +static void reload(struct ev_loop *loop) { struct route_head new_routes = TAILQ_HEAD_INITIALIZER(new_routes); struct rip_redistribute *redist; @@ -129,7 +116,7 @@ static void reload(void) struct route *r; int count = 0; - INFO("Reloading configuration"); + DEBUG("Reloading configuration"); rip_config_init(&new_rip); @@ -148,11 +135,16 @@ static void reload(void) /* Apply config via backend */ if (backend_apply(&new_routes, &new_rip)) { - ERROR("Failed applying config via backend"); + ERROR("Failed applying config via backend, retry in 5s"); route_list_free(&new_routes); rip_config_free(&new_rip); + ev_timer_stop(loop, &retry_w); + ev_timer_set(&retry_w, 5., 0.); + ev_timer_start(loop, &retry_w); + pidfile(NULL); return; } + ev_timer_stop(loop, &retry_w); route_list_free(&active_routes); TAILQ_INIT(&active_routes); @@ -214,26 +206,59 @@ static void reload(void) } } - INFO("Configuration reloaded"); pidfile(NULL); } +static void inotify_cb(struct ev_loop *loop, ev_io *w, int revents) +{ + char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; + + (void)revents; + while (read(w->fd, buf, sizeof(buf)) > 0) + ; + DEBUG("conf.d changed, triggering reload"); + reload(loop); +} + +static void sighup_cb(struct ev_loop *loop, ev_signal *w, int revents) +{ + (void)w; (void)revents; + INFO("Got SIGHUP, reloading ..."); + reload(loop); +} + +static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents) +{ + (void)w; (void)revents; + ev_break(loop, EVBREAK_ALL); +} + +static void retry_cb(struct ev_loop *loop, ev_timer *w, int revents) +{ + (void)w; (void)revents; + reload(loop); +} + static int usage(int rc) { fprintf(stderr, - "Usage: netd [-dh]\n" + "Usage: netd [-dhv]\n" " -d Enable debug (log to stderr)\n" - " -h Show this help text\n"); + " -h Show this help text\n" + " -v Show version and exit\n"); return rc; } int main(int argc, char *argv[]) { + struct ev_loop *loop = EV_DEFAULT; + ev_signal sighup_w, sigterm_w, sigint_w; + ev_io inotify_w; int log_opts = LOG_PID | LOG_NDELAY; - struct sigaction sa = { 0 }; + int ifd = -1; int c; - while ((c = getopt(argc, argv, "dhp:")) != -1) { + while ((c = getopt(argc, argv, "dhv")) != -1) { switch (c) { case 'd': log_opts |= LOG_PERROR; @@ -241,6 +266,9 @@ int main(int argc, char *argv[]) break; case 'h': return usage(0); + case 'v': + puts("v" PACKAGE_VERSION); + return 0; default: return usage(1); } @@ -248,15 +276,7 @@ int main(int argc, char *argv[]) openlog("netd", log_opts, LOG_DAEMON); setlogmask(LOG_UPTO(LOG_INFO)); - INFO("starting"); - - /* Set up signal handlers */ - sa.sa_handler = sighup_handler; - sigaction(SIGHUP, &sa, NULL); - - sa.sa_handler = sigterm_handler; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); + INFO("v%s starting", PACKAGE_VERSION); if (backend_init()) { ERROR("Failed to initialize backend"); @@ -267,19 +287,44 @@ int main(int argc, char *argv[]) TAILQ_INIT(&active_routes); rip_config_init(&active_rip); + /* Signal watchers */ + ev_signal_init(&sighup_w, sighup_cb, SIGHUP); + ev_signal_start(loop, &sighup_w); + + ev_signal_init(&sigterm_w, sigterm_cb, SIGTERM); + ev_signal_start(loop, &sigterm_w); + + ev_signal_init(&sigint_w, sigterm_cb, SIGINT); + ev_signal_start(loop, &sigint_w); + + /* Retry timer — one-shot, started only on backend failure */ + ev_timer_init(&retry_w, retry_cb, 0., 0.); + + /* Watch conf.d for changes so we don't rely solely on signals */ + mkdir(CONF_DIR, 0755); + ifd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); + if (ifd < 0) { + ERROR("inotify_init1: %s, falling back to signals only", strerror(errno)); + } else if (inotify_add_watch(ifd, CONF_DIR, + IN_CLOSE_WRITE | IN_DELETE | + IN_MOVED_TO | IN_MOVED_FROM) < 0) { + ERROR("inotify_add_watch %s: %s", CONF_DIR, strerror(errno)); + close(ifd); + ifd = -1; + } else { + ev_io_init(&inotify_w, inotify_cb, ifd, EV_READ); + ev_io_start(loop, &inotify_w); + } + /* Initial load */ - do_reload = 1; + reload(loop); - while (!do_shutdown) { - if (do_reload) { - do_reload = 0; - reload(); - } - pause(); - } + ev_run(loop, 0); INFO("shutting down"); + if (ifd >= 0) + close(ifd); route_list_free(&active_routes); rip_config_free(&active_rip); backend_cleanup(); diff --git a/src/netd/src/netd.h b/src/netd/src/netd.h index 99fb4ab21..80df72b4b 100644 --- a/src/netd/src/netd.h +++ b/src/netd/src/netd.h @@ -21,7 +21,7 @@ extern int debug; #define INFO(fmt, args...) LOG(LOG_INFO, fmt, ##args) #define DEBUG(fmt, args...) do { if (debug) LOG(LOG_DEBUG, fmt, ##args); } while (0) -#define CONF_DIR "/etc/netd/conf.d" +#define CONF_DIR "/etc/net.d" /* Nexthop types */ enum nh_type {