Skip to content

Commit e17780f

Browse files
authored
Merge pull request #1442 from kernelkit/netd-backport
Backport fix to critical v26.02.0 regression
2 parents f6f6381 + b4ea269 commit e17780f

11 files changed

Lines changed: 111 additions & 58 deletions

File tree

board/common/rootfs/etc/netd/conf.d/.empty

Whitespace-only changes.

board/common/rootfs/usr/share/udhcpc/default.script

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ACTION="$1"
77
IP_CACHE="/var/lib/misc/${interface}.cache"
88
RESOLV_CONF="/run/resolvconf/interfaces/${interface}.conf"
99
NTPFILE="/run/chrony/dhcp-sources.d/${interface}.sources"
10-
NAME="/etc/netd/conf.d/${interface}-dhcp.conf"
10+
NAME="/etc/net.d/${interface}-dhcp.conf"
1111
NEXT="${NAME}+"
1212

1313
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
@@ -118,17 +118,13 @@ set_dhcp_routes()
118118
# Reduce changes needed by comparing with previous route(s)
119119
cmp -s "$NAME" "$NEXT" && return
120120
mv "$NEXT" "$NAME"
121-
122-
initctl reload netd
123121
}
124122

125123
clr_dhcp_routes()
126124
{
127125
log "deleting DHCP routes"
128126
[ -f "$NAME" ] || return
129127
rm "$NAME"
130-
131-
initctl reload netd
132128
}
133129

134130
clr_dhcp_addresses()

doc/ChangeLog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Change Log
33

44
All notable changes to the project are documented in this file.
55

6-
[v26.02.1][] - 2026-03-11
6+
[v26.02.1][] - 2026-03-12
77
-------------------------
88

99
### Changes
@@ -17,6 +17,7 @@ All notable changes to the project are documented in this file.
1717

1818
- Fix #1389: legacy name limit in firewalld triggered problems with policy names
1919
- Fix #1416: `show firewall` command show an error when the firewall is disabled
20+
- Fix #1438: default route from DHCP client not set at boot, regression in v26.02.0
2021
- Fix instabilities in Zebra route manager after Frr upgrade in v26.02.0
2122
- Fix regression in MVEBU SafeXcel Crypto Engine for Marvell Armada SOCs (37xx,
2223
7k, 8k, and CN913x series). Firmware package lost in v26.01.0

package/netd/Config.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ config BR2_PACKAGE_NETD
22
bool "netd"
33
select BR2_PACKAGE_LIBITE
44
select BR2_PACKAGE_LIBCONFUSE
5+
select BR2_PACKAGE_LIBEV
56
help
67
Network route daemon. Manages static routes and RIP routing.
7-
Reads configuration from /etc/netd/conf.d/*.conf.
8+
Reads configuration from /etc/net.d/*.conf.
89

910
With FRR: Full routing via gRPC, vtysh, or frr.conf.
1011
Without FRR: Standalone Linux backend via rtnetlink.

package/netd/netd.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
#
55
################################################################################
66

7-
NETD_VERSION = 1.0
7+
NETD_VERSION = 1.1.0
88
NETD_SITE_METHOD = local
99
NETD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/netd
1010
NETD_LICENSE = BSD-3-Clause
1111
NETD_LICENSE_FILES = LICENSE
1212
NETD_REDISTRIBUTE = NO
13-
NETD_DEPENDENCIES = libite libconfuse jansson
13+
NETD_DEPENDENCIES = libite libconfuse jansson libev
1414
NETD_AUTORECONF = YES
1515

1616
NETD_CONF_ENV = CFLAGS="$(INFIX_CFLAGS)"

src/confd/src/routing.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#define XPATH_BASE_ "/ietf-routing:routing/control-plane-protocols/control-plane-protocol"
1010
#define XPATH_OSPF_ XPATH_BASE_ "/ietf-ospf:ospf"
11-
#define NETD_CONF "/etc/netd/conf.d/confd.conf"
11+
#define NETD_CONF "/etc/net.d/confd.conf"
1212
#define NETD_CONF_NEXT NETD_CONF "+"
1313
#define NETD_CONF_PREV NETD_CONF "-"
1414
#define OSPFD_CONF "/etc/frr/ospfd.conf"

src/netd/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ netd_SOURCES = src/netd.c src/netd.h src/config.c src/config.h
66
netd_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE -I$(srcdir)/src
77
netd_CFLAGS = -W -Wall -Wextra
88
netd_CFLAGS += $(libite_CFLAGS) $(libconfuse_CFLAGS) $(jansson_CFLAGS)
9-
netd_LDADD = $(libite_LIBS) $(libconfuse_LIBS) $(jansson_LIBS)
9+
netd_LDADD = $(libite_LIBS) $(libconfuse_LIBS) $(jansson_LIBS) $(EV_LIBS)
1010

1111
# Backend selection: FRR gRPC, FRR frr.conf, or Linux kernel
1212
if HAVE_FRR_GRPC

src/netd/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ make install
6060

6161
netd uses [libconfuse](https://github.com/martinh/libconfuse) for configuration parsing, providing a clean and structured format.
6262

63-
Configuration files are placed in `/etc/netd/conf.d/` with the `.conf` extension. Files are processed in alphabetical order.
63+
Configuration files are placed in `/etc/net.d/` with the `.conf` extension. Files are processed in alphabetical order.
6464

6565
### Configuration Format
6666

@@ -219,10 +219,10 @@ rip {
219219

220220
### Configuration Files
221221

222-
Configuration files must be placed in `/etc/netd/conf.d/` with the `.conf` extension:
222+
Configuration files must be placed in `/etc/net.d/` with the `.conf` extension:
223223

224224
```bash
225-
/etc/netd/conf.d/
225+
/etc/net.d/
226226
├── 10-static.conf # Static routes
227227
├── 20-rip.conf # RIP configuration
228228
└── 99-local.conf # Local overrides
@@ -256,7 +256,7 @@ netd validates configuration on reload. Check syslog for errors.
256256

257257
```
258258
┌─────────┐
259-
│ confd │ Writes /etc/netd/conf.d/confd.conf
259+
│ confd │ Writes /etc/net.d/confd.conf
260260
└────┬────┘
261261
│ SIGHUP
262262

src/netd/configure.ac

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
AC_PREREQ(2.61)
2-
AC_INIT([netd], [1.0.0], [https://github.com/kernelkit/infix/issues])
2+
AC_INIT([netd], [1.1.0], [https://github.com/kernelkit/infix/issues])
33
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
44
AM_SILENT_RULES(yes)
55

@@ -81,6 +81,16 @@ PKG_CHECK_MODULES([libite], [libite >= 2.6.1])
8181
PKG_CHECK_MODULES([libconfuse], [libconfuse >= 3.0])
8282
PKG_CHECK_MODULES([jansson], [jansson >= 2.0])
8383

84+
AC_CHECK_HEADER([ev.h],
85+
[saved_LIBS="$LIBS"
86+
AC_CHECK_LIB([ev], [ev_loop_new],
87+
[EV_LIBS="-lev"],
88+
[AC_MSG_ERROR("libev not found")])
89+
LIBS="$saved_LIBS"],
90+
[AC_MSG_ERROR("ev.h not found")]
91+
)
92+
AC_SUBST([EV_LIBS])
93+
8494
test "x$prefix" = xNONE && prefix=$ac_default_prefix
8595
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
8696

src/netd/src/netd.c

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
22

33
#include <errno.h>
44
#include <getopt.h>
5+
#include <sys/inotify.h>
6+
#include <ev.h>
57
#include <libite/lite.h>
68

79
#include "netd.h"
810
#include "config.h"
911

1012
int debug;
1113

12-
static sig_atomic_t do_reload;
13-
static sig_atomic_t do_shutdown;
14-
1514
static struct route_head active_routes = TAILQ_HEAD_INITIALIZER(active_routes);
1615
static struct rip_config active_rip;
1716

@@ -46,19 +45,7 @@ static int backend_apply(struct route_head *routes, struct rip_config *rip) {
4645
}
4746
#endif
4847

49-
static void sighup_handler(int sig)
50-
{
51-
(void)sig;
52-
53-
INFO("Got SIGHUP, reloading ...");
54-
do_reload = 1;
55-
}
56-
57-
static void sigterm_handler(int sig)
58-
{
59-
(void)sig;
60-
do_shutdown = 1;
61-
}
48+
static ev_timer retry_w;
6249

6350
static void route_list_free(struct route_head *head)
6451
{
@@ -118,7 +105,7 @@ static void rip_config_free(struct rip_config *cfg)
118105
}
119106
}
120107

121-
static void reload(void)
108+
static void reload(struct ev_loop *loop)
122109
{
123110
struct route_head new_routes = TAILQ_HEAD_INITIALIZER(new_routes);
124111
struct rip_redistribute *redist;
@@ -129,7 +116,7 @@ static void reload(void)
129116
struct route *r;
130117
int count = 0;
131118

132-
INFO("Reloading configuration");
119+
DEBUG("Reloading configuration");
133120

134121
rip_config_init(&new_rip);
135122

@@ -148,11 +135,16 @@ static void reload(void)
148135

149136
/* Apply config via backend */
150137
if (backend_apply(&new_routes, &new_rip)) {
151-
ERROR("Failed applying config via backend");
138+
ERROR("Failed applying config via backend, retry in 5s");
152139
route_list_free(&new_routes);
153140
rip_config_free(&new_rip);
141+
ev_timer_stop(loop, &retry_w);
142+
ev_timer_set(&retry_w, 5., 0.);
143+
ev_timer_start(loop, &retry_w);
144+
pidfile(NULL);
154145
return;
155146
}
147+
ev_timer_stop(loop, &retry_w);
156148

157149
route_list_free(&active_routes);
158150
TAILQ_INIT(&active_routes);
@@ -214,49 +206,77 @@ static void reload(void)
214206
}
215207
}
216208

217-
INFO("Configuration reloaded");
218209
pidfile(NULL);
219210
}
220211

212+
static void inotify_cb(struct ev_loop *loop, ev_io *w, int revents)
213+
{
214+
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
215+
216+
(void)revents;
217+
while (read(w->fd, buf, sizeof(buf)) > 0)
218+
;
219+
DEBUG("conf.d changed, triggering reload");
220+
reload(loop);
221+
}
222+
223+
static void sighup_cb(struct ev_loop *loop, ev_signal *w, int revents)
224+
{
225+
(void)w; (void)revents;
226+
INFO("Got SIGHUP, reloading ...");
227+
reload(loop);
228+
}
229+
230+
static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents)
231+
{
232+
(void)w; (void)revents;
233+
ev_break(loop, EVBREAK_ALL);
234+
}
235+
236+
static void retry_cb(struct ev_loop *loop, ev_timer *w, int revents)
237+
{
238+
(void)w; (void)revents;
239+
reload(loop);
240+
}
241+
221242
static int usage(int rc)
222243
{
223244
fprintf(stderr,
224-
"Usage: netd [-dh]\n"
245+
"Usage: netd [-dhv]\n"
225246
" -d Enable debug (log to stderr)\n"
226-
" -h Show this help text\n");
247+
" -h Show this help text\n"
248+
" -v Show version and exit\n");
227249
return rc;
228250
}
229251

230252
int main(int argc, char *argv[])
231253
{
254+
struct ev_loop *loop = EV_DEFAULT;
255+
ev_signal sighup_w, sigterm_w, sigint_w;
256+
ev_io inotify_w;
232257
int log_opts = LOG_PID | LOG_NDELAY;
233-
struct sigaction sa = { 0 };
258+
int ifd = -1;
234259
int c;
235260

236-
while ((c = getopt(argc, argv, "dhp:")) != -1) {
261+
while ((c = getopt(argc, argv, "dhv")) != -1) {
237262
switch (c) {
238263
case 'd':
239264
log_opts |= LOG_PERROR;
240265
debug = 1;
241266
break;
242267
case 'h':
243268
return usage(0);
269+
case 'v':
270+
puts("v" PACKAGE_VERSION);
271+
return 0;
244272
default:
245273
return usage(1);
246274
}
247275
}
248276

249277
openlog("netd", log_opts, LOG_DAEMON);
250278
setlogmask(LOG_UPTO(LOG_INFO));
251-
INFO("starting");
252-
253-
/* Set up signal handlers */
254-
sa.sa_handler = sighup_handler;
255-
sigaction(SIGHUP, &sa, NULL);
256-
257-
sa.sa_handler = sigterm_handler;
258-
sigaction(SIGTERM, &sa, NULL);
259-
sigaction(SIGINT, &sa, NULL);
279+
INFO("v%s starting", PACKAGE_VERSION);
260280

261281
if (backend_init()) {
262282
ERROR("Failed to initialize backend");
@@ -267,19 +287,44 @@ int main(int argc, char *argv[])
267287
TAILQ_INIT(&active_routes);
268288
rip_config_init(&active_rip);
269289

290+
/* Signal watchers */
291+
ev_signal_init(&sighup_w, sighup_cb, SIGHUP);
292+
ev_signal_start(loop, &sighup_w);
293+
294+
ev_signal_init(&sigterm_w, sigterm_cb, SIGTERM);
295+
ev_signal_start(loop, &sigterm_w);
296+
297+
ev_signal_init(&sigint_w, sigterm_cb, SIGINT);
298+
ev_signal_start(loop, &sigint_w);
299+
300+
/* Retry timer — one-shot, started only on backend failure */
301+
ev_timer_init(&retry_w, retry_cb, 0., 0.);
302+
303+
/* Watch conf.d for changes so we don't rely solely on signals */
304+
mkdir(CONF_DIR, 0755);
305+
ifd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
306+
if (ifd < 0) {
307+
ERROR("inotify_init1: %s, falling back to signals only", strerror(errno));
308+
} else if (inotify_add_watch(ifd, CONF_DIR,
309+
IN_CLOSE_WRITE | IN_DELETE |
310+
IN_MOVED_TO | IN_MOVED_FROM) < 0) {
311+
ERROR("inotify_add_watch %s: %s", CONF_DIR, strerror(errno));
312+
close(ifd);
313+
ifd = -1;
314+
} else {
315+
ev_io_init(&inotify_w, inotify_cb, ifd, EV_READ);
316+
ev_io_start(loop, &inotify_w);
317+
}
318+
270319
/* Initial load */
271-
do_reload = 1;
320+
reload(loop);
272321

273-
while (!do_shutdown) {
274-
if (do_reload) {
275-
do_reload = 0;
276-
reload();
277-
}
278-
pause();
279-
}
322+
ev_run(loop, 0);
280323

281324
INFO("shutting down");
282325

326+
if (ifd >= 0)
327+
close(ifd);
283328
route_list_free(&active_routes);
284329
rip_config_free(&active_rip);
285330
backend_cleanup();

0 commit comments

Comments
 (0)