Hi everyone,

this mail includes a patch to store pf rules in a red-black tree.
Currently they are stored in a linked list.
My system configured with 16000 rules takes about 10 minutes
to print them out using `pfctl -sr`.
This patch decreases the time to 4 seconds.
I was not able to measure a time increase for rule insertion.
Inserting a lot of labels is still very slow.
This has to be attacked separatly.


diff --git sbin/pfctl/parse.y sbin/pfctl/parse.y
index 8a92a7e895c..c6f8629c690 100644
--- sbin/pfctl/parse.y
+++ sbin/pfctl/parse.y
@@ -5548,11 +5548,13 @@ mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
 {
        struct pf_rule *r;
 
-       TAILQ_FOREACH(r, src->rules.active.ptr, entries)
+       RB_FOREACH(r, pf_ruletree, src->rules.active.ptr) {
                dst->anchor->match++;
-       TAILQ_CONCAT(dst->rules.active.ptr, src->rules.active.ptr, entries);
+               RB_INSERT(pf_ruletree, dst->rules.active.ptr, r);
+       }
        src->anchor->match = 0;
-       TAILQ_CONCAT(dst->rules.inactive.ptr, src->rules.inactive.ptr, entries);
+       RB_FOREACH(r, pf_ruletree, src->rules.inactive.ptr)
+               RB_INSERT(pf_ruletree, dst->rules.inactive.ptr, r);
 }
 
 void
diff --git sbin/pfctl/pfctl.c sbin/pfctl/pfctl.c
index 9f14b955ca7..49aafbed4e5 100644
--- sbin/pfctl/pfctl.c
+++ sbin/pfctl/pfctl.c
@@ -1170,7 +1170,7 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
                err(1, "calloc");
        bcopy(r, rule, sizeof(*rule));
 
-       TAILQ_INSERT_TAIL(rs->rules.active.ptr, rule, entries);
+       RB_INSERT(pf_ruletree, rs->rules.active.ptr, rule);
 }
 
 int
@@ -1409,7 +1409,7 @@ pfctl_check_qassignments(struct pf_ruleset *rs)
                }
        }
 
-       TAILQ_FOREACH(r, rs->rules.active.ptr, entries) {
+       RB_FOREACH(r, pf_ruletree, rs->rules.active.ptr) {
                if (r->anchor)
                        errs += pfctl_check_qassignments(&r->anchor->ruleset);
                if (pfctl_leafqueue_check(r->qname) ||
@@ -1436,7 +1436,7 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct 
pf_ruleset *rs,
                snprintf(&path[len], PATH_MAX - len, "%s", pf->anchor->path);
 
        if (depth) {
-               if (TAILQ_FIRST(rs->rules.active.ptr) != NULL) {
+               if (!RB_EMPTY(rs->rules.active.ptr)) {
                        brace++;
                        if (pf->opts & PF_OPT_VERBOSE)
                                printf(" {\n");
@@ -1454,8 +1454,8 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct 
pf_ruleset *rs,
        if (pf->optimize)
                pfctl_optimize_ruleset(pf, rs);
 
-       while ((r = TAILQ_FIRST(rs->rules.active.ptr)) != NULL) {
-               TAILQ_REMOVE(rs->rules.active.ptr, r, entries);
+       while ((r = RB_MIN(pf_ruletree, rs->rules.active.ptr)) != NULL) {
+               RB_REMOVE(pf_ruletree, rs->rules.active.ptr, r);
                pfctl_expand_label_nr(r, rno);
                rno++;
                if ((error = pfctl_load_rule(pf, path, r, depth)))
diff --git sbin/pfctl/pfctl_optimize.c sbin/pfctl/pfctl_optimize.c
index dc93b882bef..d0ba5c2aca4 100644
--- sbin/pfctl/pfctl_optimize.c
+++ sbin/pfctl/pfctl_optimize.c
@@ -191,6 +191,7 @@ struct pf_rule_field {
     PF_RULE_FIELD(src_nodes,           DC),
     PF_RULE_FIELD(nr,                  DC),
     PF_RULE_FIELD(entries,             DC),
+    PF_RULE_FIELD(usage,               DC),
     PF_RULE_FIELD(qid,                 DC),
     PF_RULE_FIELD(pqid,                        DC),
     PF_RULE_FIELD(anchor_relative,     DC),
@@ -268,9 +269,9 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset 
*rs)
        struct superblock *block;
        struct pf_opt_rule *por;
        struct pf_rule *r;
-       struct pf_rulequeue *old_rules;
+       struct pf_ruletree *old_rules;
 
-       if (TAILQ_EMPTY(rs->rules.active.ptr))
+       if (RB_EMPTY(rs->rules.active.ptr))
                return (0);
 
        DEBUG("optimizing ruleset \"%s\"", rs->anchor->path);
@@ -286,8 +287,8 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset 
*rs)
         * XXX expanding the pf_opt_rule format throughout pfctl might allow
         * us to avoid all this copying.
         */
-       while ((r = TAILQ_FIRST(rs->rules.inactive.ptr)) != NULL) {
-               TAILQ_REMOVE(rs->rules.inactive.ptr, r, entries);
+       while ((r = RB_MIN(pf_ruletree, rs->rules.inactive.ptr)) != NULL) {
+               RB_REMOVE(pf_ruletree, rs->rules.inactive.ptr, r);
                if ((por = calloc(1, sizeof(*por))) == NULL)
                        err(1, "calloc");
                memcpy(&por->por_rule, r, sizeof(*r));
@@ -319,7 +320,7 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset 
*rs)
                        if ((r = calloc(1, sizeof(*r))) == NULL)
                                err(1, "calloc");
                        memcpy(r, &por->por_rule, sizeof(*r));
-                       TAILQ_INSERT_TAIL(rs->rules.active.ptr, r, entries);
+                       RB_INSERT(pf_ruletree, rs->rules.active.ptr, r);
                        pf_opt_table_unref(por->por_src_tbl);
                        pf_opt_table_unref(por->por_dst_tbl);
                        free(por);
diff --git sys/net/if_pfsync.c sys/net/if_pfsync.c
index c78ca62766e..91c4fcc0493 100644
--- sys/net/if_pfsync.c
+++ sys/net/if_pfsync.c
@@ -557,7 +557,7 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
        if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
            (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
            pf_main_ruleset.rules.active.rcount) {
-               TAILQ_FOREACH(r, pf_main_ruleset.rules.active.ptr, entries)
+               RB_FOREACH(r, pf_ruletree, pf_main_ruleset.rules.active.ptr)
                        if (ntohl(sp->rule) == n++)
                                break;
        } else
diff --git sys/net/pf.c sys/net/pf.c
index f23968f07c7..3143711d455 100644
--- sys/net/pf.c
+++ sys/net/pf.c
@@ -1790,21 +1790,21 @@ pf_print_flags(u_int8_t f)
                addlog("W");
 }
 
-#define        PF_SET_SKIP_STEPS(i)                                    \
-       do {                                                    \
-               while (head[i] != cur) {                        \
-                       head[i]->skip[i].ptr = cur;             \
-                       head[i] = TAILQ_NEXT(head[i], entries); \
-               }                                               \
+#define        PF_SET_SKIP_STEPS(i)                                            
\
+       do {                                                            \
+               while (head[i] != cur) {                                \
+                       head[i]->skip[i].ptr = cur;                     \
+                       head[i] = RB_NEXT(pf_ruletree, rules, head[i]); \
+               }                                                       \
        } while (0)
 
 void
-pf_calc_skip_steps(struct pf_rulequeue *rules)
+pf_calc_skip_steps(struct pf_ruletree *rules)
 {
        struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
        int i;
 
-       cur = TAILQ_FIRST(rules);
+       cur = RB_MIN(pf_ruletree, rules);
        prev = cur;
        for (i = 0; i < PF_SKIP_COUNT; ++i)
                head[i] = cur;
@@ -1836,7 +1836,7 @@ pf_calc_skip_steps(struct pf_rulequeue *rules)
                        PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
 
                prev = cur;
-               cur = TAILQ_NEXT(cur, entries);
+               cur = RB_NEXT(pf_ruletree, rules, cur);
        }
        for (i = 0; i < PF_SKIP_COUNT; ++i)
                PF_SET_SKIP_STEPS(i);
@@ -3606,8 +3606,9 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_ruleset 
*ruleset)
        struct pf_rule  *r;
        struct pf_rule  *save_a;
        struct pf_ruleset       *save_aruleset;
+       struct pf_ruletree *head = ruleset->rules.active.ptr;
 
-       r = TAILQ_FIRST(ruleset->rules.active.ptr);
+       r = RB_MIN(pf_ruletree, head);
        while (r != NULL) {
                r->evaluations++;
                PF_TEST_ATTRIB(
@@ -3634,26 +3635,26 @@ pf_match_rule(struct pf_test_ctx *ctx, struct 
pf_ruleset *ruleset)
                case PF_VPROTO_FRAGMENT:
                        /* tcp/udp only. port_op always 0 in other cases */
                        PF_TEST_ATTRIB((r->src.port_op || r->dst.port_op),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        PF_TEST_ATTRIB((ctx->pd->proto == IPPROTO_TCP &&
                            r->flagset),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        /* icmp only. type/code always 0 in other cases */
                        PF_TEST_ATTRIB((r->type || r->code),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        /* tcp/udp only. {uid|gid}.op always 0 in other cases */
                        PF_TEST_ATTRIB((r->gid.op || r->uid.op),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        break;
 
                case IPPROTO_TCP:
                        PF_TEST_ATTRIB(((r->flagset & ctx->th->th_flags) !=
                            r->flags),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        PF_TEST_ATTRIB((r->os_fingerprint != PF_OSFP_ANY &&
                            !pf_osfp_match(pf_osfp_fingerprint(ctx->pd),
                            r->os_fingerprint)),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        /* FALLTHROUGH */
 
                case IPPROTO_UDP:
@@ -3672,14 +3673,14 @@ pf_match_rule(struct pf_test_ctx *ctx, struct 
pf_ruleset *ruleset)
                            pf_socket_lookup(ctx->pd), 1)) &&
                            !pf_match_uid(r->uid.op, r->uid.uid[0],
                            r->uid.uid[1], ctx->pd->lookup.uid)),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        /* tcp/udp only. gid.op always 0 in other cases */
                        PF_TEST_ATTRIB((r->gid.op && (ctx->pd->lookup.done ||
                            (ctx->pd->lookup.done =
                            pf_socket_lookup(ctx->pd), 1)) &&
                            !pf_match_gid(r->gid.op, r->gid.gid[0],
                            r->gid.gid[1], ctx->pd->lookup.gid)),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        break;
 
                case IPPROTO_ICMP:
@@ -3687,16 +3688,16 @@ pf_match_rule(struct pf_test_ctx *ctx, struct 
pf_ruleset *ruleset)
                        /* icmp only. type always 0 in other cases */
                        PF_TEST_ATTRIB((r->type &&
                            r->type != ctx->icmptype + 1),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        /* icmp only. type always 0 in other cases */
                        PF_TEST_ATTRIB((r->code &&
                            r->code != ctx->icmpcode + 1),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        /* icmp only. don't create states on replies */
                        PF_TEST_ATTRIB((r->keep_state && !ctx->state_icmp &&
                            (r->rule_flag & PFRULE_STATESLOPPY) == 0 &&
                            ctx->icmp_dir != PF_IN),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                        break;
 
                default:
@@ -3705,28 +3706,28 @@ pf_match_rule(struct pf_test_ctx *ctx, struct 
pf_ruleset *ruleset)
 
                PF_TEST_ATTRIB((r->rule_flag & PFRULE_FRAGMENT &&
                    ctx->pd->virtual_proto != PF_VPROTO_FRAGMENT),
-                       TAILQ_NEXT(r, entries));
+                       RB_NEXT(pf_ruletree, head, r));
                PF_TEST_ATTRIB((r->tos && !(r->tos == ctx->pd->tos)),
-                       TAILQ_NEXT(r, entries));
+                       RB_NEXT(pf_ruletree, head, r));
                PF_TEST_ATTRIB((r->prob &&
                    r->prob <= arc4random_uniform(UINT_MAX - 1) + 1),
-                       TAILQ_NEXT(r, entries));
+                       RB_NEXT(pf_ruletree, head, r));
                PF_TEST_ATTRIB((r->match_tag &&
                    !pf_match_tag(ctx->pd->m, r, &ctx->tag)),
-                       TAILQ_NEXT(r, entries));
+                       RB_NEXT(pf_ruletree, head, r));
                PF_TEST_ATTRIB((r->rcv_kif && pf_match_rcvif(ctx->pd->m, r) ==
                    r->rcvifnot),
-                       TAILQ_NEXT(r, entries));
+                       RB_NEXT(pf_ruletree, head, r));
                PF_TEST_ATTRIB((r->prio &&
                    (r->prio == PF_PRIO_ZERO ? 0 : r->prio) !=
                    ctx->pd->m->m_pkthdr.pf.prio),
-                       TAILQ_NEXT(r, entries));
+                       RB_NEXT(pf_ruletree, head, r));
 
                /* must be last! */
                if (r->pktrate.limit) {
                        pf_add_threshold(&r->pktrate);
                        PF_TEST_ATTRIB((pf_check_threshold(&r->pktrate)),
-                               TAILQ_NEXT(r, entries));
+                               RB_NEXT(pf_ruletree, head, r));
                }
 
                /* FALLTHROUGH */
@@ -3804,7 +3805,7 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_ruleset 
*ruleset)
                        ctx->a = save_a;
                        ctx->aruleset = save_aruleset;
                }
-               r = TAILQ_NEXT(r, entries);
+               r = RB_NEXT(pf_ruletree, head, r);
        }
 
        return (ctx->test_status);
diff --git sys/net/pf_ioctl.c sys/net/pf_ioctl.c
index b540afc6fe2..b4ef2dd15bb 100644
--- sys/net/pf_ioctl.c
+++ sys/net/pf_ioctl.c
@@ -218,7 +218,7 @@ pfattach(int num)
        pf_queues_inactive = &pf_queues[1];
 
        /* default rule should never be garbage collected */
-       pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
+       pf_default_rule.usage = PF_USAGE_DEFAULT;
        pf_default_rule.action = PF_PASS;
        pf_default_rule.nr = (u_int32_t)-1;
        pf_default_rule.rtableid = -1;
@@ -294,9 +294,9 @@ pf_rule_free(struct pf_rule *rule)
 }
 
 void
-pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
+pf_rm_rule(struct pf_ruletree *ruletree, struct pf_rule *rule)
 {
-       if (rulequeue != NULL) {
+       if (ruletree != NULL) {
                if (rule->states_cur == 0 && rule->src_nodes == 0) {
                        /*
                         * XXX - we need to remove the table *before* detaching
@@ -311,13 +311,14 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule 
*rule)
                        if (rule->overload_tbl)
                                pfr_detach_table(rule->overload_tbl);
                }
-               TAILQ_REMOVE(rulequeue, rule, entries);
-               rule->entries.tqe_prev = NULL;
+               RB_REMOVE(pf_ruletree, ruletree, rule);
+               rule->usage = PF_USAGE_UNUSED;
                rule->nr = (u_int32_t)-1;
        }
 
+       ///XXX: here i am
        if (rule->states_cur > 0 || rule->src_nodes > 0 ||
-           rule->entries.tqe_prev != NULL)
+           rule->usage != PF_USAGE_UNUSED)
                return;
        pf_tag_unref(rule->tag);
        pf_tag_unref(rule->match_tag);
@@ -328,7 +329,7 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule 
*rule)
        pfi_dynaddr_remove(&rule->rdr.addr);
        pfi_dynaddr_remove(&rule->nat.addr);
        pfi_dynaddr_remove(&rule->route.addr);
-       if (rulequeue == NULL) {
+       if (ruletree == NULL) {
                pf_tbladdr_remove(&rule->src.addr);
                pf_tbladdr_remove(&rule->dst.addr);
                pf_tbladdr_remove(&rule->rdr.addr);
@@ -357,7 +358,7 @@ pf_purge_rule(struct pf_rule *rule)
 
        pf_rm_rule(ruleset->rules.active.ptr, rule);
        ruleset->rules.active.rcount--;
-       TAILQ_FOREACH(rule, ruleset->rules.active.ptr, entries)
+       RB_FOREACH(rule, pf_ruletree, ruleset->rules.active.ptr)
                rule->nr = nr++;
        ruleset->rules.active.ticket++;
        pf_calc_skip_steps(ruleset->rules.active.ptr);
@@ -532,7 +533,7 @@ pf_begin_rules(u_int32_t *ticket, const char *anchor)
 
        if ((rs = pf_find_or_create_ruleset(anchor)) == NULL)
                return (EINVAL);
-       while ((rule = TAILQ_FIRST(rs->rules.inactive.ptr)) != NULL) {
+       while ((rule = RB_MIN(pf_ruletree, rs->rules.inactive.ptr)) != NULL) {
                pf_rm_rule(rs->rules.inactive.ptr, rule);
                rs->rules.inactive.rcount--;
        }
@@ -551,7 +552,7 @@ pf_rollback_rules(u_int32_t ticket, char *anchor)
        if (rs == NULL || !rs->rules.inactive.open ||
            rs->rules.inactive.ticket != ticket)
                return;
-       while ((rule = TAILQ_FIRST(rs->rules.inactive.ptr)) != NULL) {
+       while ((rule = RB_MIN(pf_ruletree, rs->rules.inactive.ptr)) != NULL) {
                pf_rm_rule(rs->rules.inactive.ptr, rule);
                rs->rules.inactive.rcount--;
        }
@@ -832,7 +833,7 @@ pf_commit_rules(u_int32_t ticket, char *anchor)
 {
        struct pf_ruleset       *rs;
        struct pf_rule          *rule;
-       struct pf_rulequeue     *old_rules;
+       struct pf_ruletree      *old_rules;
        u_int32_t                old_rcount;
 
        /* Make sure any expired rules get removed from active rules first. */
@@ -860,7 +861,7 @@ pf_commit_rules(u_int32_t ticket, char *anchor)
 
 
        /* Purge the old rule list. */
-       while ((rule = TAILQ_FIRST(old_rules)) != NULL)
+       while ((rule = RB_MIN(pf_ruletree, old_rules)) != NULL)
                pf_rm_rule(old_rules, rule);
        rs->rules.inactive.rcount = 0;
        rs->rules.inactive.open = 0;
@@ -882,9 +883,8 @@ pf_calc_chksum(struct pf_ruleset *rs)
        MD5Init(&ctx);
 
        if (rs->rules.inactive.rcount) {
-               TAILQ_FOREACH(rule, rs->rules.inactive.ptr, entries) {
+               RB_FOREACH(rule, pf_ruletree, rs->rules.inactive.ptr)
                        pf_hash_rule(&ctx, rule);
-               }
        }
 
        MD5Final(digest, &ctx);
@@ -1341,7 +1341,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
        case DIOCADDRULE: {
                struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
                struct pf_ruleset       *ruleset;
-               struct pf_rule          *rule, *tail;
+               struct pf_rule          *rule, *last;
 
                rule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL|PR_ZERO);
                if (rule == NULL) {
@@ -1402,10 +1402,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
                rule->cuid = p->p_ucred->cr_ruid;
                rule->cpid = p->p_p->ps_pid;
 
-               tail = TAILQ_LAST(ruleset->rules.inactive.ptr,
-                   pf_rulequeue);
-               if (tail)
-                       rule->nr = tail->nr + 1;
+               last = RB_MAX(pf_ruletree, ruleset->rules.inactive.ptr);
+               if (last)
+                       rule->nr = last->nr + 1;
                else
                        rule->nr = 0;
 
@@ -1442,8 +1441,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
                        NET_UNLOCK();
                        goto fail;
                }
-               TAILQ_INSERT_TAIL(ruleset->rules.inactive.ptr,
-                   rule, entries);
+               RB_INSERT(pf_ruletree, ruleset->rules.inactive.ptr, rule);
+               rule->usage = PF_USAGE_USED;
                rule->ruleset = ruleset;
                ruleset->rules.inactive.rcount++;
                PF_UNLOCK();
@@ -1454,7 +1453,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
        case DIOCGETRULES: {
                struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
                struct pf_ruleset       *ruleset;
-               struct pf_rule          *tail;
+               struct pf_rule          *last;
 
                NET_LOCK();
                PF_LOCK();
@@ -1466,9 +1465,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
                        NET_UNLOCK();
                        goto fail;
                }
-               tail = TAILQ_LAST(ruleset->rules.active.ptr, pf_rulequeue);
-               if (tail)
-                       pr->nr = tail->nr + 1;
+               last = RB_MAX(pf_ruletree, ruleset->rules.active.ptr);
+               if (last)
+                       pr->nr = last->nr + 1;
                else
                        pr->nr = 0;
                pr->ticket = ruleset->rules.active.ticket;
@@ -1499,9 +1498,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
                        NET_UNLOCK();
                        goto fail;
                }
-               rule = TAILQ_FIRST(ruleset->rules.active.ptr);
-               while ((rule != NULL) && (rule->nr != pr->nr))
-                       rule = TAILQ_NEXT(rule, entries);
+               struct pf_rule find = { .nr = pr->nr };
+               rule = RB_FIND(pf_ruletree, ruleset->rules.active.ptr, &find);
                if (rule == NULL) {
                        error = EBUSY;
                        PF_UNLOCK();
@@ -1676,14 +1674,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
                }
 
                if (pcr->action == PF_CHANGE_ADD_HEAD)
-                       oldrule = TAILQ_FIRST(ruleset->rules.active.ptr);
+                       oldrule = RB_MIN(pf_ruletree,
+                           ruleset->rules.active.ptr);
                else if (pcr->action == PF_CHANGE_ADD_TAIL)
-                       oldrule = TAILQ_LAST(ruleset->rules.active.ptr,
-                           pf_rulequeue);
+                       oldrule = RB_MAX(pf_ruletree,
+                           ruleset->rules.active.ptr);
                else {
-                       oldrule = TAILQ_FIRST(ruleset->rules.active.ptr);
+                       oldrule = RB_MIN(pf_ruletree,
+                           ruleset->rules.active.ptr);
                        while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
-                               oldrule = TAILQ_NEXT(oldrule, entries);
+                               oldrule = RB_NEXT(pf_ruletree,
+                                   ruleset->rules.active.ptr, oldrule);
                        if (oldrule == NULL) {
                                if (newrule != NULL)
                                        pf_rm_rule(NULL, newrule);
@@ -1698,23 +1699,14 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
struct proc *p)
                        pf_rm_rule(ruleset->rules.active.ptr, oldrule);
                        ruleset->rules.active.rcount--;
                } else {
-                       if (oldrule == NULL)
-                               TAILQ_INSERT_TAIL(
-                                   ruleset->rules.active.ptr,
-                                   newrule, entries);
-                       else if (pcr->action == PF_CHANGE_ADD_HEAD ||
-                           pcr->action == PF_CHANGE_ADD_BEFORE)
-                               TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
-                       else
-                               TAILQ_INSERT_AFTER(
-                                   ruleset->rules.active.ptr,
-                                   oldrule, newrule, entries);
+                       RB_INSERT(pf_ruletree,
+                           ruleset->rules.active.ptr, newrule);
                        ruleset->rules.active.rcount++;
                        newrule->ruleset = ruleset;
                }
 
                nr = 0;
-               TAILQ_FOREACH(oldrule, ruleset->rules.active.ptr, entries)
+               RB_FOREACH(oldrule, pf_ruletree, ruleset->rules.active.ptr)
                        oldrule->nr = nr++;
 
                ruleset->rules.active.ticket++;
diff --git sys/net/pf_ruleset.c sys/net/pf_ruleset.c
index 6131895751e..adf5a73dcb8 100644
--- sys/net/pf_ruleset.c
+++ sys/net/pf_ruleset.c
@@ -87,8 +87,22 @@ struct pool  pf_anchor_pl;
 struct pf_anchor_global         pf_anchors;
 struct pf_anchor        pf_main_anchor;
 
+static __inline int pf_rule_compare(struct pf_rule *, struct pf_rule *);
 static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
 
+RB_GENERATE(pf_ruletree, pf_rule, entries, pf_rule_compare);
+
+static __inline int
+pf_rule_compare(struct pf_rule *a, struct pf_rule *b)
+{
+       if (a->nr == b->nr)
+               return (0);
+       else if (a->nr > b->nr)
+               return (1);
+       else
+               return (-1);
+}
+
 RB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
 RB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
 
@@ -104,10 +118,10 @@ void
 pf_init_ruleset(struct pf_ruleset *ruleset)
 {
        memset(ruleset, 0, sizeof(struct pf_ruleset));
-       TAILQ_INIT(&ruleset->rules.queues[0]);
-       TAILQ_INIT(&ruleset->rules.queues[1]);
-       ruleset->rules.active.ptr = &ruleset->rules.queues[0];
-       ruleset->rules.inactive.ptr = &ruleset->rules.queues[1];
+       RB_INIT(&ruleset->rules.trees[0]);
+       RB_INIT(&ruleset->rules.trees[1]);
+       ruleset->rules.active.ptr = &ruleset->rules.trees[0];
+       ruleset->rules.inactive.ptr = &ruleset->rules.trees[1];
 }
 
 struct pf_anchor *
@@ -300,8 +314,8 @@ pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
                    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
                    ruleset->topen)
                        return;
-               if (!TAILQ_EMPTY(ruleset->rules.active.ptr) ||
-                   !TAILQ_EMPTY(ruleset->rules.inactive.ptr) ||
+               if (!RB_EMPTY(ruleset->rules.active.ptr) ||
+                   !RB_EMPTY(ruleset->rules.inactive.ptr) ||
                    ruleset->rules.inactive.open)
                        return;
                RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
diff --git sys/net/pfvar.h sys/net/pfvar.h
index 6f88ff687ed..4e3b877856c 100644
--- sys/net/pfvar.h
+++ sys/net/pfvar.h
@@ -506,7 +506,11 @@ struct pf_rule {
 
        char                     overload_tblname[PF_TABLE_NAME_SIZE];
 
-       TAILQ_ENTRY(pf_rule)     entries;
+       RB_ENTRY(pf_rule)        entries;
+#define PF_USAGE_UNUSED                0
+#define PF_USAGE_USED          1
+#define PF_USAGE_DEFAULT       2
+       uint8_t                  usage;
        struct pf_pool           nat;
        struct pf_pool           rdr;
        struct pf_pool           route;
@@ -918,15 +922,15 @@ struct pfsync_state {
        d += ntohl(s[1]);                                       \
 } while (0)
 
-TAILQ_HEAD(pf_rulequeue, pf_rule);
+RB_HEAD(pf_ruletree, pf_rule);
 
 struct pf_anchor;
 
 struct pf_ruleset {
        struct {
-               struct pf_rulequeue      queues[2];
+               struct pf_ruletree       trees[2];
                struct {
-                       struct pf_rulequeue     *ptr;
+                       struct pf_ruletree      *ptr;
                        u_int32_t                rcount;
                        u_int32_t                ticket;
                        int                      open;
@@ -937,6 +941,7 @@ struct pf_ruleset {
        int                      tables;
        int                      topen;
 };
+RB_PROTOTYPE(pf_ruletree, pf_rule, entries, pf_rule_compare)
 
 RB_HEAD(pf_anchor_global, pf_anchor);
 RB_HEAD(pf_anchor_node, pf_anchor);
@@ -1454,7 +1459,7 @@ struct pf_pktdelay {
 #define PFFRAG_FRENT_HIWAT     (NMBCLUSTERS / 16) /* Number of entries */
 #define PFFRAG_FRAG_HIWAT      (NMBCLUSTERS / 32) /* Number of packets */
 
-#define PFR_KTABLE_HIWAT       1000    /* Number of tables */
+#define PFR_KTABLE_HIWAT       50000   /* Number of tables */
 #define PFR_KENTRY_HIWAT       200000  /* Number of table entries */
 #define PFR_KENTRY_HIWAT_SMALL 100000  /* Number of entries for tiny hosts */
 
@@ -1713,7 +1718,7 @@ extern int                         
pf_tbladdr_setup(struct pf_ruleset *,
                                    struct pf_addr_wrap *, int);
 extern void                     pf_tbladdr_remove(struct pf_addr_wrap *);
 extern void                     pf_tbladdr_copyout(struct pf_addr_wrap *);
-extern void                     pf_calc_skip_steps(struct pf_rulequeue *);
+extern void                     pf_calc_skip_steps(struct pf_ruletree *);
 extern void                     pf_purge_expired_src_nodes(void);
 extern void                     pf_purge_expired_states(u_int32_t);
 extern void                     pf_purge_expired_rules(void);
@@ -1744,7 +1749,7 @@ extern void                        pf_print_state(struct 
pf_state *);
 extern void                     pf_print_flags(u_int8_t);
 extern void                     pf_addrcpy(struct pf_addr *, struct pf_addr *,
                                    sa_family_t);
-void                            pf_rm_rule(struct pf_rulequeue *,
+void                            pf_rm_rule(struct pf_ruletree *,
                                    struct pf_rule *);
 void                            pf_purge_rule(struct pf_rule *);
 struct pf_divert               *pf_find_divert(struct mbuf *);


Best Regards,
Stefan Butz

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to