From: Stuart Henderson Subject: Re: [PATCH] Allow 'set queue' in dynamic anchor updates (v2) To: Jon Bentley Cc: "tech@openbsd.org" Date: Mon, 23 Jun 2025 12:09:34 +0100 On 2025/06/23 08:27, Jon Bentley wrote: > (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. :-) In both cases, the diff is mangled, whitespace is not maintained (tabs were converted to spaces). > 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() */ >