From: Jon Bentley Subject: [PATCH] Allow 'set queue' in dynamic anchor updates (v3) To: tech@openbsd.org Date: Tue, 24 Jun 2025 03:32:11 -0400 (Switched to mutt, all text/plain now, tabs, etc.) If you have existing queues and try to dynamically update an anchor: # pfctl -a myanchor -F rules -f myanchor.rules It will fail on any rules with 'set queue'. This patch preloads queues to fix this. --- diff --git sbin/pfctl/pfctl.c sbin/pfctl/pfctl.c index 96f7b9dac06..dd052bff3d7 100644 --- sbin/pfctl/pfctl.c +++ sbin/pfctl/pfctl.c @@ -122,6 +122,9 @@ int pfctl_call_cleartables(int, int, struct pfr_anchoritem *); int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *); int pfctl_call_showtables(int, int, struct pfr_anchoritem *); +/* Preload queues for dynamic anchor updates. */ +extern void pfctl_preload_queues(int dev, struct pf_qihead *qhead); + const char *clearopt; char *rulesopt; const char *showopt; @@ -2970,6 +2973,12 @@ main(int argc, char *argv[]) } if (rulesopt != NULL) { + /* Do we need to pre-load the table and queue definitions? */ + if (anchorname[0]) { + /* Preload queues for dynamic anchor updates. */ + pfctl_preload_queues(dev, &qspecs); + } /* if (working with an anchor) */ + if (pfctl_rules(dev, rulesopt, opts, optimize, anchorname, NULL)) exit_val = 1; diff --git sbin/pfctl/pfctl_queue.c sbin/pfctl/pfctl_queue.c index 1f0d456300c..7792007bda3 100644 --- sbin/pfctl/pfctl_queue.c +++ sbin/pfctl/pfctl_queue.c @@ -71,6 +71,9 @@ void pfctl_print_queue_nodestat(int, void update_avg(struct queue_stats *); char *rate2str(double); +/* Preload queues for dynamic anchor updates. */ +void pfctl_preload_queues(int dev, struct pf_qihead *qhead); + int pfctl_show_queues(int dev, const char *iface, int opts, int verbose2) { @@ -285,3 +288,32 @@ rate2str(double rate) return (buf); } + +/* Preload queues for dynamic anchor updates. */ +void pfctl_preload_queues(int dev, struct pf_qihead *qhead) +{ + struct pfctl_queue_node *node; /* Transfer node. */ + struct pfctl_qsitem *qi; /* Transfer item. */ + + /* Pull in the current queue definitions. */ + pfctl_update_qstats(dev); + + /* Loop through each queue. */ + TAILQ_FOREACH(node, &qnodes, entries) { + /* Allocate and pre-clear a new queue item. */ + qi = calloc(1, sizeof(*qi)); + + /* Check for allocation failure. */ + if (qi == NULL) + err(1, "pfctl_preload_queues: calloc"); + + /* Copy over the existing queue specification. */ + bcopy(&node->qs, &qi->qs, sizeof(qi->qs)); + + /* Initialize the child pointer. */ + TAILQ_INIT(&qi->children); + + /* Insert this into the main definition. */ + TAILQ_INSERT_TAIL(&qspecs, qi, entries); + } +} /* pfctl_preload_queues() */