2 * Copyright (c) 2005 Philip Paeps <philip@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/queue.h>
30 #include <bsnmp/snmpmod.h>
32 #include <net/pfvar.h>
33 #include <sys/ioctl.h>
47 struct lmodule *module;
51 static uint64_t pf_tick;
53 static struct pf_status pfs;
59 #define PFI_IFTYPE_GROUP 0
60 #define PFI_IFTYPE_INSTANCE 1
61 #define PFI_IFTYPE_DETACHED 2
66 TAILQ_ENTRY(pfi_entry) link;
68 TAILQ_HEAD(pfi_table, pfi_entry);
70 static struct pfi_table pfi_table;
71 static time_t pfi_table_age;
72 static int pfi_table_count;
74 #define PFI_TABLE_MAXAGE 5
77 struct pfr_tstats pft;
79 TAILQ_ENTRY(pft_entry) link;
81 TAILQ_HEAD(pft_table, pft_entry);
83 static struct pft_table pft_table;
84 static time_t pft_table_age;
85 static int pft_table_count;
87 #define PFT_TABLE_MAXAGE 5
90 struct pfr_astats pfas;
92 TAILQ_ENTRY(pfa_entry) link;
94 TAILQ_HEAD(pfa_table, pfa_entry);
96 static struct pfa_table pfa_table;
97 static time_t pfa_table_age;
98 static int pfa_table_count;
100 #define PFA_TABLE_MAXAGE 5
105 TAILQ_ENTRY(pfq_entry) link;
107 TAILQ_HEAD(pfq_table, pfq_entry);
109 static struct pfq_table pfq_table;
110 static time_t pfq_table_age;
111 static int pfq_table_count;
113 static int altq_enabled = 0;
115 #define PFQ_TABLE_MAXAGE 5
118 char name[MAXPATHLEN + PF_RULE_LABEL_SIZE];
123 TAILQ_ENTRY(pfl_entry) link;
125 TAILQ_HEAD(pfl_table, pfl_entry);
127 static struct pfl_table pfl_table;
128 static time_t pfl_table_age;
129 static int pfl_table_count;
131 #define PFL_TABLE_MAXAGE 5
133 /* Forward declarations */
134 static int pfi_refresh(void);
135 static int pfq_refresh(void);
136 static int pfs_refresh(void);
137 static int pft_refresh(void);
138 static int pfa_refresh(void);
139 static int pfl_refresh(void);
140 static struct pfi_entry * pfi_table_find(u_int idx);
141 static struct pfq_entry * pfq_table_find(u_int idx);
142 static struct pft_entry * pft_table_find(u_int idx);
143 static struct pfa_entry * pfa_table_find(u_int idx);
144 static struct pfl_entry * pfl_table_find(u_int idx);
146 static int altq_is_enabled(int pfdevice);
149 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
150 u_int sub, u_int __unused vindex, enum snmp_op op)
152 asn_subid_t which = val->var.subs[sub - 1];
154 unsigned char str[128];
156 if (op == SNMP_OP_SET)
157 return (SNMP_ERR_NOT_WRITEABLE);
159 if (op == SNMP_OP_GET) {
160 if (pfs_refresh() == -1)
161 return (SNMP_ERR_GENERR);
164 case LEAF_pfStatusRunning:
165 val->v.uint32 = pfs.running;
167 case LEAF_pfStatusRuntime:
168 runtime = (pfs.since > 0) ?
169 time(NULL) - pfs.since : 0;
170 val->v.uint32 = runtime * 100;
172 case LEAF_pfStatusDebug:
173 val->v.uint32 = pfs.debug;
175 case LEAF_pfStatusHostId:
176 sprintf(str, "0x%08x", ntohl(pfs.hostid));
177 return (string_get(val, str, strlen(str)));
180 return (SNMP_ERR_NOSUCHNAME);
183 return (SNMP_ERR_NOERROR);
190 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
191 u_int sub, u_int __unused vindex, enum snmp_op op)
193 asn_subid_t which = val->var.subs[sub - 1];
195 if (op == SNMP_OP_SET)
196 return (SNMP_ERR_NOT_WRITEABLE);
198 if (op == SNMP_OP_GET) {
199 if (pfs_refresh() == -1)
200 return (SNMP_ERR_GENERR);
203 case LEAF_pfCounterMatch:
204 val->v.counter64 = pfs.counters[PFRES_MATCH];
206 case LEAF_pfCounterBadOffset:
207 val->v.counter64 = pfs.counters[PFRES_BADOFF];
209 case LEAF_pfCounterFragment:
210 val->v.counter64 = pfs.counters[PFRES_FRAG];
212 case LEAF_pfCounterShort:
213 val->v.counter64 = pfs.counters[PFRES_SHORT];
215 case LEAF_pfCounterNormalize:
216 val->v.counter64 = pfs.counters[PFRES_NORM];
218 case LEAF_pfCounterMemDrop:
219 val->v.counter64 = pfs.counters[PFRES_MEMORY];
223 return (SNMP_ERR_NOSUCHNAME);
226 return (SNMP_ERR_NOERROR);
233 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
234 u_int sub, u_int __unused vindex, enum snmp_op op)
236 asn_subid_t which = val->var.subs[sub - 1];
238 if (op == SNMP_OP_SET)
239 return (SNMP_ERR_NOT_WRITEABLE);
241 if (op == SNMP_OP_GET) {
242 if (pfs_refresh() == -1)
243 return (SNMP_ERR_GENERR);
246 case LEAF_pfStateTableCount:
247 val->v.uint32 = pfs.states;
249 case LEAF_pfStateTableSearches:
251 pfs.fcounters[FCNT_STATE_SEARCH];
253 case LEAF_pfStateTableInserts:
255 pfs.fcounters[FCNT_STATE_INSERT];
257 case LEAF_pfStateTableRemovals:
259 pfs.fcounters[FCNT_STATE_REMOVALS];
263 return (SNMP_ERR_NOSUCHNAME);
266 return (SNMP_ERR_NOERROR);
273 pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,
274 u_int sub, u_int __unused vindex, enum snmp_op op)
276 asn_subid_t which = val->var.subs[sub - 1];
278 if (op == SNMP_OP_SET)
279 return (SNMP_ERR_NOT_WRITEABLE);
281 if (op == SNMP_OP_GET) {
282 if (pfs_refresh() == -1)
283 return (SNMP_ERR_GENERR);
286 case LEAF_pfSrcNodesCount:
287 val->v.uint32 = pfs.src_nodes;
289 case LEAF_pfSrcNodesSearches:
291 pfs.scounters[SCNT_SRC_NODE_SEARCH];
293 case LEAF_pfSrcNodesInserts:
295 pfs.scounters[SCNT_SRC_NODE_INSERT];
297 case LEAF_pfSrcNodesRemovals:
299 pfs.scounters[SCNT_SRC_NODE_REMOVALS];
303 return (SNMP_ERR_NOSUCHNAME);
306 return (SNMP_ERR_NOERROR);
313 pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
314 u_int sub, u_int __unused vindex, enum snmp_op op)
316 asn_subid_t which = val->var.subs[sub - 1];
317 struct pfioc_limit pl;
319 if (op == SNMP_OP_SET)
320 return (SNMP_ERR_NOT_WRITEABLE);
322 if (op == SNMP_OP_GET) {
323 bzero(&pl, sizeof(struct pfioc_limit));
326 case LEAF_pfLimitsStates:
327 pl.index = PF_LIMIT_STATES;
329 case LEAF_pfLimitsSrcNodes:
330 pl.index = PF_LIMIT_SRC_NODES;
332 case LEAF_pfLimitsFrags:
333 pl.index = PF_LIMIT_FRAGS;
337 return (SNMP_ERR_NOSUCHNAME);
340 if (ioctl(dev, DIOCGETLIMIT, &pl)) {
341 syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
343 return (SNMP_ERR_GENERR);
346 val->v.uint32 = pl.limit;
348 return (SNMP_ERR_NOERROR);
355 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
356 u_int sub, u_int __unused vindex, enum snmp_op op)
358 asn_subid_t which = val->var.subs[sub - 1];
361 if (op == SNMP_OP_SET)
362 return (SNMP_ERR_NOT_WRITEABLE);
364 if (op == SNMP_OP_GET) {
365 bzero(&pt, sizeof(struct pfioc_tm));
368 case LEAF_pfTimeoutsTcpFirst:
369 pt.timeout = PFTM_TCP_FIRST_PACKET;
371 case LEAF_pfTimeoutsTcpOpening:
372 pt.timeout = PFTM_TCP_OPENING;
374 case LEAF_pfTimeoutsTcpEstablished:
375 pt.timeout = PFTM_TCP_ESTABLISHED;
377 case LEAF_pfTimeoutsTcpClosing:
378 pt.timeout = PFTM_TCP_CLOSING;
380 case LEAF_pfTimeoutsTcpFinWait:
381 pt.timeout = PFTM_TCP_FIN_WAIT;
383 case LEAF_pfTimeoutsTcpClosed:
384 pt.timeout = PFTM_TCP_CLOSED;
386 case LEAF_pfTimeoutsUdpFirst:
387 pt.timeout = PFTM_UDP_FIRST_PACKET;
389 case LEAF_pfTimeoutsUdpSingle:
390 pt.timeout = PFTM_UDP_SINGLE;
392 case LEAF_pfTimeoutsUdpMultiple:
393 pt.timeout = PFTM_UDP_MULTIPLE;
395 case LEAF_pfTimeoutsIcmpFirst:
396 pt.timeout = PFTM_ICMP_FIRST_PACKET;
398 case LEAF_pfTimeoutsIcmpError:
399 pt.timeout = PFTM_ICMP_ERROR_REPLY;
401 case LEAF_pfTimeoutsOtherFirst:
402 pt.timeout = PFTM_OTHER_FIRST_PACKET;
404 case LEAF_pfTimeoutsOtherSingle:
405 pt.timeout = PFTM_OTHER_SINGLE;
407 case LEAF_pfTimeoutsOtherMultiple:
408 pt.timeout = PFTM_OTHER_MULTIPLE;
410 case LEAF_pfTimeoutsFragment:
411 pt.timeout = PFTM_FRAG;
413 case LEAF_pfTimeoutsInterval:
414 pt.timeout = PFTM_INTERVAL;
416 case LEAF_pfTimeoutsAdaptiveStart:
417 pt.timeout = PFTM_ADAPTIVE_START;
419 case LEAF_pfTimeoutsAdaptiveEnd:
420 pt.timeout = PFTM_ADAPTIVE_END;
422 case LEAF_pfTimeoutsSrcNode:
423 pt.timeout = PFTM_SRC_NODE;
427 return (SNMP_ERR_NOSUCHNAME);
430 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
431 syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
433 return (SNMP_ERR_GENERR);
436 val->v.integer = pt.seconds;
438 return (SNMP_ERR_NOERROR);
445 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
446 u_int sub, u_int __unused vindex, enum snmp_op op)
448 asn_subid_t which = val->var.subs[sub - 1];
449 unsigned char str[IFNAMSIZ];
451 if (op == SNMP_OP_SET)
452 return (SNMP_ERR_NOT_WRITEABLE);
454 if (op == SNMP_OP_GET) {
455 if (pfs_refresh() == -1)
456 return (SNMP_ERR_GENERR);
459 case LEAF_pfLogInterfaceName:
460 strlcpy(str, pfs.ifname, sizeof str);
461 return (string_get(val, str, strlen(str)));
462 case LEAF_pfLogInterfaceIp4BytesIn:
463 val->v.counter64 = pfs.bcounters[IPV4][IN];
465 case LEAF_pfLogInterfaceIp4BytesOut:
466 val->v.counter64 = pfs.bcounters[IPV4][OUT];
468 case LEAF_pfLogInterfaceIp4PktsInPass:
470 pfs.pcounters[IPV4][IN][PF_PASS];
472 case LEAF_pfLogInterfaceIp4PktsInDrop:
474 pfs.pcounters[IPV4][IN][PF_DROP];
476 case LEAF_pfLogInterfaceIp4PktsOutPass:
478 pfs.pcounters[IPV4][OUT][PF_PASS];
480 case LEAF_pfLogInterfaceIp4PktsOutDrop:
482 pfs.pcounters[IPV4][OUT][PF_DROP];
484 case LEAF_pfLogInterfaceIp6BytesIn:
485 val->v.counter64 = pfs.bcounters[IPV6][IN];
487 case LEAF_pfLogInterfaceIp6BytesOut:
488 val->v.counter64 = pfs.bcounters[IPV6][OUT];
490 case LEAF_pfLogInterfaceIp6PktsInPass:
492 pfs.pcounters[IPV6][IN][PF_PASS];
494 case LEAF_pfLogInterfaceIp6PktsInDrop:
496 pfs.pcounters[IPV6][IN][PF_DROP];
498 case LEAF_pfLogInterfaceIp6PktsOutPass:
500 pfs.pcounters[IPV6][OUT][PF_PASS];
502 case LEAF_pfLogInterfaceIp6PktsOutDrop:
504 pfs.pcounters[IPV6][OUT][PF_DROP];
508 return (SNMP_ERR_NOSUCHNAME);
511 return (SNMP_ERR_NOERROR);
518 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
519 u_int sub, u_int __unused vindex, enum snmp_op op)
521 asn_subid_t which = val->var.subs[sub - 1];
523 if (op == SNMP_OP_SET)
524 return (SNMP_ERR_NOT_WRITEABLE);
526 if (op == SNMP_OP_GET) {
527 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
528 if (pfi_refresh() == -1)
529 return (SNMP_ERR_GENERR);
532 case LEAF_pfInterfacesIfNumber:
533 val->v.uint32 = pfi_table_count;
537 return (SNMP_ERR_NOSUCHNAME);
540 return (SNMP_ERR_NOERROR);
547 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
548 u_int sub, u_int __unused vindex, enum snmp_op op)
550 asn_subid_t which = val->var.subs[sub - 1];
551 struct pfi_entry *e = NULL;
553 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
558 return (SNMP_ERR_NOT_WRITEABLE);
559 case SNMP_OP_GETNEXT:
560 if ((e = NEXT_OBJECT_INT(&pfi_table,
561 &val->var, sub)) == NULL)
562 return (SNMP_ERR_NOSUCHNAME);
563 val->var.len = sub + 1;
564 val->var.subs[sub] = e->index;
567 if (val->var.len - sub != 1)
568 return (SNMP_ERR_NOSUCHNAME);
569 if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
570 return (SNMP_ERR_NOSUCHNAME);
574 case SNMP_OP_ROLLBACK:
580 case LEAF_pfInterfacesIfDescr:
581 return (string_get(val, e->pfi.pfik_name, -1));
582 case LEAF_pfInterfacesIfType:
583 val->v.integer = PFI_IFTYPE_INSTANCE;
585 case LEAF_pfInterfacesIfTZero:
587 (time(NULL) - e->pfi.pfik_tzero) * 100;
589 case LEAF_pfInterfacesIfRefsRule:
590 val->v.uint32 = e->pfi.pfik_rulerefs;
592 case LEAF_pfInterfacesIf4BytesInPass:
594 e->pfi.pfik_bytes[IPV4][IN][PASS];
596 case LEAF_pfInterfacesIf4BytesInBlock:
598 e->pfi.pfik_bytes[IPV4][IN][BLOCK];
600 case LEAF_pfInterfacesIf4BytesOutPass:
602 e->pfi.pfik_bytes[IPV4][OUT][PASS];
604 case LEAF_pfInterfacesIf4BytesOutBlock:
606 e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
608 case LEAF_pfInterfacesIf4PktsInPass:
610 e->pfi.pfik_packets[IPV4][IN][PASS];
612 case LEAF_pfInterfacesIf4PktsInBlock:
614 e->pfi.pfik_packets[IPV4][IN][BLOCK];
616 case LEAF_pfInterfacesIf4PktsOutPass:
618 e->pfi.pfik_packets[IPV4][OUT][PASS];
620 case LEAF_pfInterfacesIf4PktsOutBlock:
622 e->pfi.pfik_packets[IPV4][OUT][BLOCK];
624 case LEAF_pfInterfacesIf6BytesInPass:
626 e->pfi.pfik_bytes[IPV6][IN][PASS];
628 case LEAF_pfInterfacesIf6BytesInBlock:
630 e->pfi.pfik_bytes[IPV6][IN][BLOCK];
632 case LEAF_pfInterfacesIf6BytesOutPass:
634 e->pfi.pfik_bytes[IPV6][OUT][PASS];
636 case LEAF_pfInterfacesIf6BytesOutBlock:
638 e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
640 case LEAF_pfInterfacesIf6PktsInPass:
642 e->pfi.pfik_packets[IPV6][IN][PASS];
644 case LEAF_pfInterfacesIf6PktsInBlock:
646 e->pfi.pfik_packets[IPV6][IN][BLOCK];
648 case LEAF_pfInterfacesIf6PktsOutPass:
650 e->pfi.pfik_packets[IPV6][OUT][PASS];
652 case LEAF_pfInterfacesIf6PktsOutBlock:
654 e->pfi.pfik_packets[IPV6][OUT][BLOCK];
658 return (SNMP_ERR_NOSUCHNAME);
661 return (SNMP_ERR_NOERROR);
665 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
666 u_int sub, u_int __unused vindex, enum snmp_op op)
668 asn_subid_t which = val->var.subs[sub - 1];
670 if (op == SNMP_OP_SET)
671 return (SNMP_ERR_NOT_WRITEABLE);
673 if (op == SNMP_OP_GET) {
674 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
675 if (pft_refresh() == -1)
676 return (SNMP_ERR_GENERR);
679 case LEAF_pfTablesTblNumber:
680 val->v.uint32 = pft_table_count;
684 return (SNMP_ERR_NOSUCHNAME);
687 return (SNMP_ERR_NOERROR);
694 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
695 u_int sub, u_int __unused vindex, enum snmp_op op)
697 asn_subid_t which = val->var.subs[sub - 1];
698 struct pft_entry *e = NULL;
700 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
705 return (SNMP_ERR_NOT_WRITEABLE);
706 case SNMP_OP_GETNEXT:
707 if ((e = NEXT_OBJECT_INT(&pft_table,
708 &val->var, sub)) == NULL)
709 return (SNMP_ERR_NOSUCHNAME);
710 val->var.len = sub + 1;
711 val->var.subs[sub] = e->index;
714 if (val->var.len - sub != 1)
715 return (SNMP_ERR_NOSUCHNAME);
716 if ((e = pft_table_find(val->var.subs[sub])) == NULL)
717 return (SNMP_ERR_NOSUCHNAME);
721 case SNMP_OP_ROLLBACK:
727 case LEAF_pfTablesTblDescr:
728 return (string_get(val, e->pft.pfrts_name, -1));
729 case LEAF_pfTablesTblCount:
730 val->v.integer = e->pft.pfrts_cnt;
732 case LEAF_pfTablesTblTZero:
734 (time(NULL) - e->pft.pfrts_tzero) * 100;
736 case LEAF_pfTablesTblRefsAnchor:
738 e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
740 case LEAF_pfTablesTblRefsRule:
742 e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
744 case LEAF_pfTablesTblEvalMatch:
745 val->v.counter64 = e->pft.pfrts_match;
747 case LEAF_pfTablesTblEvalNoMatch:
748 val->v.counter64 = e->pft.pfrts_nomatch;
750 case LEAF_pfTablesTblBytesInPass:
752 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
754 case LEAF_pfTablesTblBytesInBlock:
756 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
758 case LEAF_pfTablesTblBytesInXPass:
760 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
762 case LEAF_pfTablesTblBytesOutPass:
764 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
766 case LEAF_pfTablesTblBytesOutBlock:
768 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
770 case LEAF_pfTablesTblBytesOutXPass:
772 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
774 case LEAF_pfTablesTblPktsInPass:
776 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
778 case LEAF_pfTablesTblPktsInBlock:
780 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
782 case LEAF_pfTablesTblPktsInXPass:
784 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
786 case LEAF_pfTablesTblPktsOutPass:
788 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
790 case LEAF_pfTablesTblPktsOutBlock:
792 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
794 case LEAF_pfTablesTblPktsOutXPass:
796 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
800 return (SNMP_ERR_NOSUCHNAME);
803 return (SNMP_ERR_NOERROR);
807 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
808 u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
810 asn_subid_t which = val->var.subs[sub - 1];
811 struct pfa_entry *e = NULL;
813 if ((time(NULL) - pfa_table_age) > PFA_TABLE_MAXAGE)
818 return (SNMP_ERR_NOT_WRITEABLE);
819 case SNMP_OP_GETNEXT:
820 if ((e = NEXT_OBJECT_INT(&pfa_table,
821 &val->var, sub)) == NULL)
822 return (SNMP_ERR_NOSUCHNAME);
823 val->var.len = sub + 1;
824 val->var.subs[sub] = e->index;
827 if (val->var.len - sub != 1)
828 return (SNMP_ERR_NOSUCHNAME);
829 if ((e = pfa_table_find(val->var.subs[sub])) == NULL)
830 return (SNMP_ERR_NOSUCHNAME);
834 case SNMP_OP_ROLLBACK:
840 case LEAF_pfTablesAddrNetType:
841 if (e->pfas.pfras_a.pfra_af == AF_INET)
842 val->v.integer = pfTablesAddrNetType_ipv4;
843 else if (e->pfas.pfras_a.pfra_af == AF_INET6)
844 val->v.integer = pfTablesAddrNetType_ipv6;
846 return (SNMP_ERR_GENERR);
848 case LEAF_pfTablesAddrNet:
849 if (e->pfas.pfras_a.pfra_af == AF_INET) {
850 return (string_get(val,
851 (u_char *)&e->pfas.pfras_a.pfra_ip4addr, 4));
852 } else if (e->pfas.pfras_a.pfra_af == AF_INET6)
853 return (string_get(val,
854 (u_char *)&e->pfas.pfras_a.pfra_ip6addr, 16));
856 return (SNMP_ERR_GENERR);
858 case LEAF_pfTablesAddrPrefix:
859 val->v.integer = (int32_t) e->pfas.pfras_a.pfra_net;
861 case LEAF_pfTablesAddrTZero:
863 (time(NULL) - e->pfas.pfras_tzero) * 100;
865 case LEAF_pfTablesAddrBytesInPass:
867 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_PASS];
869 case LEAF_pfTablesAddrBytesInBlock:
871 e->pfas.pfras_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
873 case LEAF_pfTablesAddrBytesOutPass:
875 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_PASS];
877 case LEAF_pfTablesAddrBytesOutBlock:
879 e->pfas.pfras_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
881 case LEAF_pfTablesAddrPktsInPass:
883 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_PASS];
885 case LEAF_pfTablesAddrPktsInBlock:
887 e->pfas.pfras_packets[PFR_DIR_IN][PFR_OP_BLOCK];
889 case LEAF_pfTablesAddrPktsOutPass:
891 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_PASS];
893 case LEAF_pfTablesAddrPktsOutBlock:
895 e->pfas.pfras_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
898 return (SNMP_ERR_NOSUCHNAME);
901 return (SNMP_ERR_NOERROR);
905 pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
906 u_int sub, u_int __unused vindex, enum snmp_op op)
908 asn_subid_t which = val->var.subs[sub - 1];
911 return (SNMP_ERR_NOSUCHNAME);
913 if (op == SNMP_OP_SET)
914 return (SNMP_ERR_NOT_WRITEABLE);
916 if (op == SNMP_OP_GET) {
917 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
918 if (pfq_refresh() == -1)
919 return (SNMP_ERR_GENERR);
922 case LEAF_pfAltqQueueNumber:
923 val->v.uint32 = pfq_table_count;
927 return (SNMP_ERR_NOSUCHNAME);
930 return (SNMP_ERR_NOERROR);
934 return (SNMP_ERR_GENERR);
938 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
939 u_int sub, u_int __unused vindex, enum snmp_op op)
941 asn_subid_t which = val->var.subs[sub - 1];
942 struct pfq_entry *e = NULL;
945 return (SNMP_ERR_NOSUCHNAME);
947 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
952 return (SNMP_ERR_NOT_WRITEABLE);
953 case SNMP_OP_GETNEXT:
954 if ((e = NEXT_OBJECT_INT(&pfq_table,
955 &val->var, sub)) == NULL)
956 return (SNMP_ERR_NOSUCHNAME);
957 val->var.len = sub + 1;
958 val->var.subs[sub] = e->index;
961 if (val->var.len - sub != 1)
962 return (SNMP_ERR_NOSUCHNAME);
963 if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
964 return (SNMP_ERR_NOSUCHNAME);
968 case SNMP_OP_ROLLBACK:
974 case LEAF_pfAltqQueueDescr:
975 return (string_get(val, e->altq.qname, -1));
976 case LEAF_pfAltqQueueParent:
977 return (string_get(val, e->altq.parent, -1));
978 case LEAF_pfAltqQueueScheduler:
979 val->v.integer = e->altq.scheduler;
981 case LEAF_pfAltqQueueBandwidth:
982 val->v.uint32 = e->altq.bandwidth;
984 case LEAF_pfAltqQueuePriority:
985 val->v.integer = e->altq.priority;
987 case LEAF_pfAltqQueueLimit:
988 val->v.integer = e->altq.qlimit;
992 return (SNMP_ERR_NOSUCHNAME);
995 return (SNMP_ERR_NOERROR);
999 pf_labels(struct snmp_context __unused *ctx, struct snmp_value *val,
1000 u_int sub, u_int __unused vindex, enum snmp_op op)
1002 asn_subid_t which = val->var.subs[sub - 1];
1004 if (op == SNMP_OP_SET)
1005 return (SNMP_ERR_NOT_WRITEABLE);
1007 if (op == SNMP_OP_GET) {
1008 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1009 if (pfl_refresh() == -1)
1010 return (SNMP_ERR_GENERR);
1013 case LEAF_pfLabelsLblNumber:
1014 val->v.uint32 = pfl_table_count;
1018 return (SNMP_ERR_NOSUCHNAME);
1021 return (SNMP_ERR_NOERROR);
1025 return (SNMP_ERR_GENERR);
1029 pf_lbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
1030 u_int sub, u_int __unused vindex, enum snmp_op op)
1032 asn_subid_t which = val->var.subs[sub - 1];
1033 struct pfl_entry *e = NULL;
1035 if ((time(NULL) - pfl_table_age) > PFL_TABLE_MAXAGE)
1040 return (SNMP_ERR_NOT_WRITEABLE);
1041 case SNMP_OP_GETNEXT:
1042 if ((e = NEXT_OBJECT_INT(&pfl_table,
1043 &val->var, sub)) == NULL)
1044 return (SNMP_ERR_NOSUCHNAME);
1045 val->var.len = sub + 1;
1046 val->var.subs[sub] = e->index;
1049 if (val->var.len - sub != 1)
1050 return (SNMP_ERR_NOSUCHNAME);
1051 if ((e = pfl_table_find(val->var.subs[sub])) == NULL)
1052 return (SNMP_ERR_NOSUCHNAME);
1055 case SNMP_OP_COMMIT:
1056 case SNMP_OP_ROLLBACK:
1062 case LEAF_pfLabelsLblName:
1063 return (string_get(val, e->name, -1));
1064 case LEAF_pfLabelsLblEvals:
1065 val->v.counter64 = e->evals;
1067 case LEAF_pfLabelsLblBytesIn:
1068 val->v.counter64 = e->bytes[IN];
1070 case LEAF_pfLabelsLblBytesOut:
1071 val->v.counter64 = e->bytes[OUT];
1073 case LEAF_pfLabelsLblPktsIn:
1074 val->v.counter64 = e->pkts[IN];
1076 case LEAF_pfLabelsLblPktsOut:
1077 val->v.counter64 = e->pkts[OUT];
1080 return (SNMP_ERR_NOSUCHNAME);
1083 return (SNMP_ERR_NOERROR);
1086 static struct pfi_entry *
1087 pfi_table_find(u_int idx)
1089 struct pfi_entry *e;
1091 TAILQ_FOREACH(e, &pfi_table, link)
1092 if (e->index == idx)
1097 static struct pfq_entry *
1098 pfq_table_find(u_int idx)
1100 struct pfq_entry *e;
1102 TAILQ_FOREACH(e, &pfq_table, link)
1103 if (e->index == idx)
1108 static struct pft_entry *
1109 pft_table_find(u_int idx)
1111 struct pft_entry *e;
1113 TAILQ_FOREACH(e, &pft_table, link)
1114 if (e->index == idx)
1119 static struct pfa_entry *
1120 pfa_table_find(u_int idx)
1122 struct pfa_entry *e;
1124 TAILQ_FOREACH(e, &pfa_table, link)
1125 if (e->index == idx)
1130 static struct pfl_entry *
1131 pfl_table_find(u_int idx)
1133 struct pfl_entry *e;
1135 TAILQ_FOREACH(e, &pfl_table, link)
1136 if (e->index == idx)
1145 struct pfioc_iface io;
1146 struct pfi_kif *p = NULL;
1147 struct pfi_entry *e;
1150 if (started && this_tick <= pf_tick)
1153 while (!TAILQ_EMPTY(&pfi_table)) {
1154 e = TAILQ_FIRST(&pfi_table);
1155 TAILQ_REMOVE(&pfi_table, e, link);
1159 bzero(&io, sizeof(io));
1160 io.pfiio_esize = sizeof(struct pfi_kif);
1163 p = reallocf(p, numifs * sizeof(struct pfi_kif));
1165 syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
1166 numifs, strerror(errno));
1169 io.pfiio_size = numifs;
1170 io.pfiio_buffer = p;
1172 if (ioctl(dev, DIOCIGETIFACES, &io)) {
1173 syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
1178 if (numifs >= io.pfiio_size)
1181 numifs = io.pfiio_size;
1184 for (i = 0; i < numifs; i++) {
1185 e = malloc(sizeof(struct pfi_entry));
1189 memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
1190 TAILQ_INSERT_TAIL(&pfi_table, e, link);
1193 pfi_table_age = time(NULL);
1194 pfi_table_count = numifs;
1195 pf_tick = this_tick;
1201 while (!TAILQ_EMPTY(&pfi_table)) {
1202 e = TAILQ_FIRST(&pfi_table);
1203 TAILQ_REMOVE(&pfi_table, e, link);
1214 struct pfioc_altq pa;
1215 struct pfq_entry *e;
1216 int i, numqs, ticket;
1218 if (started && this_tick <= pf_tick)
1221 while (!TAILQ_EMPTY(&pfq_table)) {
1222 e = TAILQ_FIRST(&pfq_table);
1223 TAILQ_REMOVE(&pfq_table, e, link);
1227 bzero(&pa, sizeof(pa));
1229 if (ioctl(dev, DIOCGETALTQS, &pa)) {
1230 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
1238 for (i = 0; i < numqs; i++) {
1239 e = malloc(sizeof(struct pfq_entry));
1241 syslog(LOG_ERR, "pfq_refresh(): "
1249 if (ioctl(dev, DIOCGETALTQ, &pa)) {
1250 syslog(LOG_ERR, "pfq_refresh(): "
1251 "ioctl(DIOCGETALTQ): %s",
1256 if (pa.altq.qid > 0) {
1257 memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1258 e->index = pa.altq.qid;
1259 pfq_table_count = i;
1260 INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
1264 pfq_table_age = time(NULL);
1265 pf_tick = this_tick;
1270 while (!TAILQ_EMPTY(&pfq_table)) {
1271 e = TAILQ_FIRST(&pfq_table);
1272 TAILQ_REMOVE(&pfq_table, e, link);
1281 if (started && this_tick <= pf_tick)
1284 bzero(&pfs, sizeof(struct pf_status));
1286 if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1287 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1292 pf_tick = this_tick;
1299 struct pfioc_table io;
1300 struct pfr_tstats *t = NULL;
1301 struct pft_entry *e;
1304 if (started && this_tick <= pf_tick)
1307 while (!TAILQ_EMPTY(&pft_table)) {
1308 e = TAILQ_FIRST(&pft_table);
1309 TAILQ_REMOVE(&pft_table, e, link);
1313 bzero(&io, sizeof(io));
1314 io.pfrio_esize = sizeof(struct pfr_tstats);
1317 t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1319 syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1320 numtbls, strerror(errno));
1323 io.pfrio_size = numtbls;
1324 io.pfrio_buffer = t;
1326 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1327 syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1332 if (numtbls >= io.pfrio_size)
1335 numtbls = io.pfrio_size;
1338 for (i = 0; i < numtbls; i++) {
1339 e = malloc(sizeof(struct pft_entry));
1343 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1344 TAILQ_INSERT_TAIL(&pft_table, e, link);
1347 pft_table_age = time(NULL);
1348 pft_table_count = numtbls;
1349 pf_tick = this_tick;
1354 while (!TAILQ_EMPTY(&pft_table)) {
1355 e = TAILQ_FIRST(&pft_table);
1356 TAILQ_REMOVE(&pft_table, e, link);
1365 pfa_table_addrs(u_int sidx, struct pfr_table *pt)
1367 struct pfioc_table io;
1368 struct pfr_astats *t = NULL;
1369 struct pfa_entry *e;
1370 int i, numaddrs = 1;
1375 memset(&io, 0, sizeof(io));
1376 strlcpy(io.pfrio_table.pfrt_name, pt->pfrt_name,
1377 sizeof(io.pfrio_table.pfrt_name));
1380 t = reallocf(t, numaddrs * sizeof(struct pfr_astats));
1382 syslog(LOG_ERR, "pfa_table_addrs(): reallocf(): %s",
1388 memset(t, 0, sizeof(*t));
1389 io.pfrio_size = numaddrs;
1390 io.pfrio_buffer = t;
1391 io.pfrio_esize = sizeof(struct pfr_astats);
1393 if (ioctl(dev, DIOCRGETASTATS, &io)) {
1394 syslog(LOG_ERR, "pfa_table_addrs(): ioctl() on %s: %s",
1395 pt->pfrt_name, strerror(errno));
1400 if (numaddrs >= io.pfrio_size)
1403 numaddrs = io.pfrio_size;
1406 for (i = 0; i < numaddrs; i++) {
1407 if ((t + i)->pfras_a.pfra_af != AF_INET &&
1408 (t + i)->pfras_a.pfra_af != AF_INET6) {
1413 e = (struct pfa_entry *)malloc(sizeof(struct pfa_entry));
1415 syslog(LOG_ERR, "pfa_table_addrs(): malloc(): %s",
1420 e->index = sidx + i;
1421 memcpy(&e->pfas, t + i, sizeof(struct pfr_astats));
1422 TAILQ_INSERT_TAIL(&pfa_table, e, link);
1433 struct pfioc_table io;
1434 struct pfr_table *pt = NULL, *it = NULL;
1435 struct pfa_entry *e;
1436 int i, numtbls = 1, cidx, naddrs;
1438 if (started && this_tick <= pf_tick)
1441 while (!TAILQ_EMPTY(&pfa_table)) {
1442 e = TAILQ_FIRST(&pfa_table);
1443 TAILQ_REMOVE(&pfa_table, e, link);
1447 memset(&io, 0, sizeof(io));
1448 io.pfrio_esize = sizeof(struct pfr_table);
1451 pt = reallocf(pt, numtbls * sizeof(struct pfr_table));
1453 syslog(LOG_ERR, "pfa_refresh(): reallocf() %s",
1457 memset(pt, 0, sizeof(*pt));
1458 io.pfrio_size = numtbls;
1459 io.pfrio_buffer = pt;
1461 if (ioctl(dev, DIOCRGETTABLES, &io)) {
1462 syslog(LOG_ERR, "pfa_refresh(): ioctl(): %s",
1467 if (numtbls >= io.pfrio_size)
1470 numtbls = io.pfrio_size;
1475 for (it = pt, i = 0; i < numtbls; it++, i++) {
1477 * Skip the table if not active - ioctl(DIOCRGETASTATS) will
1478 * return ESRCH for this entry anyway.
1480 if (!(it->pfrt_flags & PFR_TFLAG_ACTIVE))
1483 if ((naddrs = pfa_table_addrs(cidx, it)) < 0)
1489 pfa_table_age = time(NULL);
1490 pfa_table_count = cidx;
1491 pf_tick = this_tick;
1496 while (!TAILQ_EMPTY(&pfa_table)) {
1497 e = TAILQ_FIRST(&pfa_table);
1498 TAILQ_REMOVE(&pfa_table, e, link);
1508 pfl_scan_ruleset(const char *path)
1510 struct pfioc_rule pr;
1511 struct pfl_entry *e;
1514 bzero(&pr, sizeof(pr));
1515 strlcpy(pr.anchor, path, sizeof(pr.anchor));
1516 pr.rule.action = PF_PASS;
1517 if (ioctl(dev, DIOCGETRULES, &pr)) {
1518 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULES): %s",
1523 for (nr = pr.nr, i = 0; i < nr; i++) {
1525 if (ioctl(dev, DIOCGETRULE, &pr)) {
1526 syslog(LOG_ERR, "pfl_scan_ruleset: ioctl(DIOCGETRULE):"
1527 " %s", strerror(errno));
1531 if (pr.rule.label[0]) {
1532 e = (struct pfl_entry *)malloc(sizeof(*e));
1536 strlcpy(e->name, path, sizeof(e->name));
1538 strlcat(e->name, "/", sizeof(e->name));
1539 strlcat(e->name, pr.rule.label, sizeof(e->name));
1541 e->evals = pr.rule.evaluations;
1542 e->bytes[IN] = pr.rule.bytes[IN];
1543 e->bytes[OUT] = pr.rule.bytes[OUT];
1544 e->pkts[IN] = pr.rule.packets[IN];
1545 e->pkts[OUT] = pr.rule.packets[OUT];
1546 e->index = ++pfl_table_count;
1548 TAILQ_INSERT_TAIL(&pfl_table, e, link);
1559 pfl_walk_rulesets(const char *path)
1561 struct pfioc_ruleset prs;
1562 char newpath[MAXPATHLEN];
1565 if (pfl_scan_ruleset(path))
1568 bzero(&prs, sizeof(prs));
1569 strlcpy(prs.path, path, sizeof(prs.path));
1570 if (ioctl(dev, DIOCGETRULESETS, &prs)) {
1571 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESETS): %s",
1576 for (nr = prs.nr, i = 0; i < nr; i++) {
1578 if (ioctl(dev, DIOCGETRULESET, &prs)) {
1579 syslog(LOG_ERR, "pfl_walk_rulesets: ioctl(DIOCGETRULESET):"
1580 " %s", strerror(errno));
1584 if (strcmp(prs.name, PF_RESERVED_ANCHOR) == 0)
1587 strlcpy(newpath, path, sizeof(newpath));
1589 strlcat(newpath, "/", sizeof(newpath));
1591 strlcat(newpath, prs.name, sizeof(newpath));
1592 if (pfl_walk_rulesets(newpath))
1605 struct pfl_entry *e;
1607 if (started && this_tick <= pf_tick)
1610 while (!TAILQ_EMPTY(&pfl_table)) {
1611 e = TAILQ_FIRST(&pfl_table);
1612 TAILQ_REMOVE(&pfl_table, e, link);
1615 pfl_table_count = 0;
1617 if (pfl_walk_rulesets(""))
1620 pfl_table_age = time(NULL);
1621 pf_tick = this_tick;
1626 while (!TAILQ_EMPTY(&pfl_table)) {
1627 e = TAILQ_FIRST(&pfl_table);
1628 TAILQ_REMOVE(&pfl_table, e, link);
1631 pfl_table_count = 0;
1637 * check whether altq support is enabled in kernel
1641 altq_is_enabled(int pfdev)
1643 struct pfioc_altq pa;
1646 if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1647 if (errno == ENODEV) {
1648 syslog(LOG_INFO, "No ALTQ support in kernel\n"
1649 "ALTQ related functions disabled\n");
1652 syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1660 * Implement the bsnmpd module interface
1663 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1667 if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1668 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1673 if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1674 syslog(LOG_ERR, "pf_init(): altq test failed");
1678 /* Prepare internal state */
1679 TAILQ_INIT(&pfi_table);
1680 TAILQ_INIT(&pfq_table);
1681 TAILQ_INIT(&pft_table);
1682 TAILQ_INIT(&pfa_table);
1683 TAILQ_INIT(&pfl_table);
1703 struct pfi_entry *i1, *i2;
1704 struct pfq_entry *q1, *q2;
1705 struct pft_entry *t1, *t2;
1706 struct pfa_entry *a1, *a2;
1707 struct pfl_entry *l1, *l2;
1709 /* Empty the list of interfaces */
1710 i1 = TAILQ_FIRST(&pfi_table);
1711 while (i1 != NULL) {
1712 i2 = TAILQ_NEXT(i1, link);
1717 /* List of queues */
1718 q1 = TAILQ_FIRST(&pfq_table);
1719 while (q1 != NULL) {
1720 q2 = TAILQ_NEXT(q1, link);
1725 /* List of tables */
1726 t1 = TAILQ_FIRST(&pft_table);
1727 while (t1 != NULL) {
1728 t2 = TAILQ_NEXT(t1, link);
1733 /* List of table addresses */
1734 a1 = TAILQ_FIRST(&pfa_table);
1735 while (a1 != NULL) {
1736 a2 = TAILQ_NEXT(a1, link);
1741 /* And the list of labeled filter rules */
1742 l1 = TAILQ_FIRST(&pfl_table);
1743 while (l1 != NULL) {
1744 l2 = TAILQ_NEXT(l1, link);
1764 syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1765 (intmax_t)pfi_table_age);
1766 syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1769 syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1770 (intmax_t)pfq_table_age);
1771 syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1774 syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1775 (intmax_t)pft_table_age);
1776 syslog(LOG_ERR, "Dump: pft_table_count = %d",
1779 syslog(LOG_ERR, "Dump: pfa_table_age = %jd",
1780 (intmax_t)pfa_table_age);
1781 syslog(LOG_ERR, "Dump: pfa_table_count = %d",
1784 syslog(LOG_ERR, "Dump: pfl_table_age = %jd",
1785 (intmax_t)pfl_table_age);
1786 syslog(LOG_ERR, "Dump: pfl_table_count = %d",
1790 const struct snmp_module config = {
1791 .comment = "This module implements a MIB for the pf packet filter.",
1796 .tree_size = pf_CTREE_SIZE,