From 1776dcb7317ef1daab3d73c6262609c1ce6e0ee1 Mon Sep 17 00:00:00 2001 From: Hayato Kiwata Date: Fri, 30 Oct 2026 01:28:58 +0900 Subject: fwd, conf: Roll back to old rules if switching to new ones fails If fwd_listen_init() fails while switching to new forwarding rules received from pesto, we currently close the old listening sockets, report an error and keep the (partially bound) new rules. That leaves pasta in a state the user didn't ask for. Make fwd_listen_switch() return the result of fwd_listen_init(), and call it a second time from conf_handler() on failure to switch back to the old rules. Don't reset the count of the old table after closing its sockets, so that the old rules stay in c->fwd_pending and can be restored. The pending tables are cleared by conf_handler() before receiving new rules anyway. Note that reporting the failure to the client is left for a later patch. Link: https://archives.passt.top/passt-dev/20261025153025.600a4fe9@elisabeth/ Signed-off-by: Hayato Kiwata Signed-off-by: Stefano Brivio --- conf.c | 7 ++++++- fwd.c | 10 +++++----- fwd.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/conf.c b/conf.c index 4a07884..2e18a66 100644 --- a/conf.c +++ b/conf.c @@ -2250,7 +2250,12 @@ void conf_handler(struct ctx *c, uint32_t events) " ", ""); } - fwd_listen_switch(c); + if (fwd_listen_switch(c) < 0) { + err("Error switching to new forwarding rules"); + /* Switch back to old rules (still in c->fwd_pending) */ + if (fwd_listen_switch(c) < 0) + err("Couldn't restore old forwarding rules"); + } } if (events & EPOLLHUP) { diff --git a/fwd.c b/fwd.c index 5679a3d..a081664 100644 --- a/fwd.c +++ b/fwd.c @@ -536,8 +536,10 @@ int fwd_listen_init(const struct ctx *c) /** * fwd_listen_switch() - Switch from current to pending rules table * @c: Execution context + * + * Return: 0 on success, -1 on failure */ -void fwd_listen_switch(struct ctx *c) +int fwd_listen_switch(struct ctx *c) { struct fwd_table *tmp[PIF_NUM_TYPES]; unsigned i; @@ -549,9 +551,8 @@ void fwd_listen_switch(struct ctx *c) if (!fwd) continue; - debug("Flushing %u old %s rules", fwd->count, pif_name(i)); + debug("Flushing %u %s rules", fwd->count, pif_name(i)); fwd_listen_close(fwd); - fwd->count = fwd->sock_count = 0; } /* Swap active and pending tables */ @@ -563,8 +564,7 @@ void fwd_listen_switch(struct ctx *c) memcpy((void *)c->fwd_pending, &tmp, sizeof(c->fwd_pending)); /* Start listening on the new tables */ - if (fwd_listen_init(c) < 0) - err("Error switching to new forwarding rules"); + return fwd_listen_init(c); } /* See enum in kernel's include/net/tcp_states.h */ diff --git a/fwd.h b/fwd.h index b60697d..a6c7bd8 100644 --- a/fwd.h +++ b/fwd.h @@ -61,7 +61,7 @@ int fwd_listen_sync(const struct ctx *c, uint8_t pif, const struct fwd_scan *tcp, const struct fwd_scan *udp); void fwd_listen_close(const struct fwd_table *fwd); int fwd_listen_init(const struct ctx *c); -void fwd_listen_switch(struct ctx *c); +int fwd_listen_switch(struct ctx *c); bool nat_inbound(const struct ctx *c, const union inany_addr *addr, union inany_addr *translated); -- cgit v1.2.3