Merge pull request #1442 from kernelkit/netd-backport

Backport fix to critical v26.02.0 regression
This commit is contained in:
Joachim Wiberg
2026-03-12 16:10:14 +01:00
committed by GitHub
11 changed files with 111 additions and 58 deletions
@@ -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()
+2 -1
View File
@@ -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
+2 -1
View File
@@ -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.
+2 -2
View File
@@ -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)"
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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
+11 -1
View File
@@ -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}'
+86 -41
View File
@@ -2,6 +2,8 @@
#include <errno.h>
#include <getopt.h>
#include <sys/inotify.h>
#include <ev.h>
#include <libite/lite.h>
#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);
/* Initial load */
do_reload = 1;
/* Signal watchers */
ev_signal_init(&sighup_w, sighup_cb, SIGHUP);
ev_signal_start(loop, &sighup_w);
while (!do_shutdown) {
if (do_reload) {
do_reload = 0;
reload();
}
pause();
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 */
reload(loop);
ev_run(loop, 0);
INFO("shutting down");
if (ifd >= 0)
close(ifd);
route_list_free(&active_routes);
rip_config_free(&active_rip);
backend_cleanup();
+1 -1
View File
@@ -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 {