When pf is disabled (pfctl -d), pf_remove_queues() detaches hfsc from the
interface but the queues are not removed from pf_queues_active.

The next time pf rules are loaded, pf_commit_queues() calls pf_remove_queues()
and in turn hfsc_delqueue() for each queue in pf_queues_active. This fails
since hfsc has already been detached.

Example:

# echo 'queue root on em0 bandwidth 2M default' > /tmp/pf.conf
# pfctl -f /tmp/pf.conf
# pfctl -d
# sudo pfctl -f /tmp/pf.conf
pfctl: DIOCXCOMMIT: Invalid argument

Also, if queues are loaded after pf is disabled they become immediately
active rather than remaining inactive until pf is enabled. Example:

# pfctl -Fa
# pfctl -d
# pfctl -f /tmp/pf.conf
# pfctl -vs queue
  [ pkts:          0  bytes:          0  dropped pkts:      0 bytes:      0 ]
  [ qlength:   0/ 50 ]
queue root on em0 bandwidth 2M default qlimit 50
  [ pkts:        180  bytes:      25352  dropped pkts:      0 bytes:      0 ]
  [ qlength:   0/ 50 ]

The diff below also allows 'pfctl -vs queue' to show zeros rather than an
error when pf is disabled.

Nathanael

Index: sys/net/pf_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.272
diff -u -p -r1.272 pf_ioctl.c
--- sys/net/pf_ioctl.c  22 Apr 2014 14:41:03 -0000      1.272
+++ sys/net/pf_ioctl.c  1 Jul 2014 12:36:08 -0000
@@ -591,7 +591,7 @@ pf_commit_queues(void)
        struct pf_queuehead     *qswap;
        int error;
 
-       if ((error = pf_remove_queues(NULL)) != 0)
+       if (pf_status.running && (error = pf_remove_queues(NULL)) != 0)
                return (error);
 
        /* swap */
@@ -600,7 +600,9 @@ pf_commit_queues(void)
        pf_queues_inactive = qswap;
        pf_free_queues(pf_queues_inactive, NULL);
 
-       return (pf_create_queues());
+       if (pf_status.running && (error = pf_create_queues()) != 0)
+               return (error);
+       return (0);
 }
 
 #define PF_MD5_UPD(st, elm)                                            \
@@ -1004,8 +1006,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
                        break;
                }
                bcopy(qs, &pq->queue, sizeof(pq->queue));
-               error = hfsc_qstats(qs, pq->buf, &nbytes);
-               if (error == 0)
+               pq->nbytes = 0;
+               if (pf_status.running &&
+                   (error = hfsc_qstats(qs, pq->buf, &nbytes)) == 0)
                        pq->nbytes = nbytes;
                break;
        }

Reply via email to