Index | Thread | Search

From:
Jon Bentley <wirewhisk@ymail.com>
Subject:
[PATCH] Allow 'set queue' in dynamic anchor updates (v3)
To:
tech@openbsd.org
Date:
Tue, 24 Jun 2025 03:32:11 -0400

Download raw body.

Thread
  • Jon Bentley:

    [PATCH] Allow 'set queue' in dynamic anchor updates (v3)

(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() */