From: Jon Bentley Subject: [PATCH] Allow 'set queue' in dynamic anchor updates (v2) To: "tech@openbsd.org" Date: Mon, 23 Jun 2025 08:27:05 +0000 (n.b. I really hate it when I forget to switch to text mode. Sorry about that!) (Thank you to Omar for pointing out my idiocy. :-) If you have existing queues and try to dynamically update an anchor with:      # 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..2cb362473e4 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,34 @@ 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() */