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 <bsnmp/snmpmod.h>
31 #include <net/pfvar.h>
32 #include <sys/ioctl.h>
46 struct lmodule *module;
50 static uint64_t pf_tick;
52 static struct pf_status pfs;
58 #define PFI_IFTYPE_GROUP 0
59 #define PFI_IFTYPE_INSTANCE 1
60 #define PFI_IFTYPE_DETACHED 2
65 TAILQ_ENTRY(pfi_entry) link;
67 TAILQ_HEAD(pfi_table, pfi_entry);
69 static struct pfi_table pfi_table;
70 static time_t pfi_table_age;
71 static int pfi_table_count;
73 #define PFI_TABLE_MAXAGE 5
76 struct pfr_tstats pft;
78 TAILQ_ENTRY(pft_entry) link;
80 TAILQ_HEAD(pft_table, pft_entry);
82 static struct pft_table pft_table;
83 static time_t pft_table_age;
84 static int pft_table_count;
86 #define PFT_TABLE_MAXAGE 5
91 TAILQ_ENTRY(pfq_entry) link;
93 TAILQ_HEAD(pfq_table, pfq_entry);
95 static struct pfq_table pfq_table;
96 static time_t pfq_table_age;
97 static int pfq_table_count;
99 static int altq_enabled = 0;
101 #define PFQ_TABLE_MAXAGE 5
103 /* Forward declarations */
104 static int pfi_refresh(void);
105 static int pfq_refresh(void);
106 static int pfs_refresh(void);
107 static int pft_refresh(void);
108 static struct pfi_entry * pfi_table_find(u_int idx);
109 static struct pfq_entry * pfq_table_find(u_int idx);
110 static struct pft_entry * pft_table_find(u_int idx);
112 static int altq_is_enabled(int pfdevice);
115 pf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
116 u_int sub, u_int __unused vindex, enum snmp_op op)
118 asn_subid_t which = val->var.subs[sub - 1];
120 unsigned char str[128];
122 if (op == SNMP_OP_SET)
123 return (SNMP_ERR_NOT_WRITEABLE);
125 if (op == SNMP_OP_GET) {
126 if (pfs_refresh() == -1)
127 return (SNMP_ERR_GENERR);
130 case LEAF_pfStatusRunning:
131 val->v.uint32 = pfs.running;
133 case LEAF_pfStatusRuntime:
134 runtime = (pfs.since > 0) ?
135 time(NULL) - pfs.since : 0;
136 val->v.uint32 = runtime * 100;
138 case LEAF_pfStatusDebug:
139 val->v.uint32 = pfs.debug;
141 case LEAF_pfStatusHostId:
142 sprintf(str, "0x%08x", ntohl(pfs.hostid));
143 return (string_get(val, str, strlen(str)));
146 return (SNMP_ERR_NOSUCHNAME);
149 return (SNMP_ERR_NOERROR);
156 pf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
157 u_int sub, u_int __unused vindex, enum snmp_op op)
159 asn_subid_t which = val->var.subs[sub - 1];
161 if (op == SNMP_OP_SET)
162 return (SNMP_ERR_NOT_WRITEABLE);
164 if (op == SNMP_OP_GET) {
165 if (pfs_refresh() == -1)
166 return (SNMP_ERR_GENERR);
169 case LEAF_pfCounterMatch:
170 val->v.counter64 = pfs.counters[PFRES_MATCH];
172 case LEAF_pfCounterBadOffset:
173 val->v.counter64 = pfs.counters[PFRES_BADOFF];
175 case LEAF_pfCounterFragment:
176 val->v.counter64 = pfs.counters[PFRES_FRAG];
178 case LEAF_pfCounterShort:
179 val->v.counter64 = pfs.counters[PFRES_SHORT];
181 case LEAF_pfCounterNormalize:
182 val->v.counter64 = pfs.counters[PFRES_NORM];
184 case LEAF_pfCounterMemDrop:
185 val->v.counter64 = pfs.counters[PFRES_MEMORY];
189 return (SNMP_ERR_NOSUCHNAME);
192 return (SNMP_ERR_NOERROR);
199 pf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
200 u_int sub, u_int __unused vindex, enum snmp_op op)
202 asn_subid_t which = val->var.subs[sub - 1];
204 if (op == SNMP_OP_SET)
205 return (SNMP_ERR_NOT_WRITEABLE);
207 if (op == SNMP_OP_GET) {
208 if (pfs_refresh() == -1)
209 return (SNMP_ERR_GENERR);
212 case LEAF_pfStateTableCount:
213 val->v.uint32 = pfs.states;
215 case LEAF_pfStateTableSearches:
217 pfs.fcounters[FCNT_STATE_SEARCH];
219 case LEAF_pfStateTableInserts:
221 pfs.fcounters[FCNT_STATE_INSERT];
223 case LEAF_pfStateTableRemovals:
225 pfs.fcounters[FCNT_STATE_REMOVALS];
229 return (SNMP_ERR_NOSUCHNAME);
232 return (SNMP_ERR_NOERROR);
239 pf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,
240 u_int sub, u_int __unused vindex, enum snmp_op op)
242 asn_subid_t which = val->var.subs[sub - 1];
244 if (op == SNMP_OP_SET)
245 return (SNMP_ERR_NOT_WRITEABLE);
247 if (op == SNMP_OP_GET) {
248 if (pfs_refresh() == -1)
249 return (SNMP_ERR_GENERR);
252 case LEAF_pfSrcNodesCount:
253 val->v.uint32 = pfs.src_nodes;
255 case LEAF_pfSrcNodesSearches:
257 pfs.scounters[SCNT_SRC_NODE_SEARCH];
259 case LEAF_pfSrcNodesInserts:
261 pfs.scounters[SCNT_SRC_NODE_INSERT];
263 case LEAF_pfSrcNodesRemovals:
265 pfs.scounters[SCNT_SRC_NODE_REMOVALS];
269 return (SNMP_ERR_NOSUCHNAME);
272 return (SNMP_ERR_NOERROR);
279 pf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
280 u_int sub, u_int __unused vindex, enum snmp_op op)
282 asn_subid_t which = val->var.subs[sub - 1];
283 struct pfioc_limit pl;
285 if (op == SNMP_OP_SET)
286 return (SNMP_ERR_NOT_WRITEABLE);
288 if (op == SNMP_OP_GET) {
289 bzero(&pl, sizeof(struct pfioc_limit));
292 case LEAF_pfLimitsStates:
293 pl.index = PF_LIMIT_STATES;
295 case LEAF_pfLimitsSrcNodes:
296 pl.index = PF_LIMIT_SRC_NODES;
298 case LEAF_pfLimitsFrags:
299 pl.index = PF_LIMIT_FRAGS;
303 return (SNMP_ERR_NOSUCHNAME);
306 if (ioctl(dev, DIOCGETLIMIT, &pl)) {
307 syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
309 return (SNMP_ERR_GENERR);
312 val->v.uint32 = pl.limit;
314 return (SNMP_ERR_NOERROR);
321 pf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
322 u_int sub, u_int __unused vindex, enum snmp_op op)
324 asn_subid_t which = val->var.subs[sub - 1];
327 if (op == SNMP_OP_SET)
328 return (SNMP_ERR_NOT_WRITEABLE);
330 if (op == SNMP_OP_GET) {
331 bzero(&pt, sizeof(struct pfioc_tm));
334 case LEAF_pfTimeoutsTcpFirst:
335 pt.timeout = PFTM_TCP_FIRST_PACKET;
337 case LEAF_pfTimeoutsTcpOpening:
338 pt.timeout = PFTM_TCP_OPENING;
340 case LEAF_pfTimeoutsTcpEstablished:
341 pt.timeout = PFTM_TCP_ESTABLISHED;
343 case LEAF_pfTimeoutsTcpClosing:
344 pt.timeout = PFTM_TCP_CLOSING;
346 case LEAF_pfTimeoutsTcpFinWait:
347 pt.timeout = PFTM_TCP_FIN_WAIT;
349 case LEAF_pfTimeoutsTcpClosed:
350 pt.timeout = PFTM_TCP_CLOSED;
352 case LEAF_pfTimeoutsUdpFirst:
353 pt.timeout = PFTM_UDP_FIRST_PACKET;
355 case LEAF_pfTimeoutsUdpSingle:
356 pt.timeout = PFTM_UDP_SINGLE;
358 case LEAF_pfTimeoutsUdpMultiple:
359 pt.timeout = PFTM_UDP_MULTIPLE;
361 case LEAF_pfTimeoutsIcmpFirst:
362 pt.timeout = PFTM_ICMP_FIRST_PACKET;
364 case LEAF_pfTimeoutsIcmpError:
365 pt.timeout = PFTM_ICMP_ERROR_REPLY;
367 case LEAF_pfTimeoutsOtherFirst:
368 pt.timeout = PFTM_OTHER_FIRST_PACKET;
370 case LEAF_pfTimeoutsOtherSingle:
371 pt.timeout = PFTM_OTHER_SINGLE;
373 case LEAF_pfTimeoutsOtherMultiple:
374 pt.timeout = PFTM_OTHER_MULTIPLE;
376 case LEAF_pfTimeoutsFragment:
377 pt.timeout = PFTM_FRAG;
379 case LEAF_pfTimeoutsInterval:
380 pt.timeout = PFTM_INTERVAL;
382 case LEAF_pfTimeoutsAdaptiveStart:
383 pt.timeout = PFTM_ADAPTIVE_START;
385 case LEAF_pfTimeoutsAdaptiveEnd:
386 pt.timeout = PFTM_ADAPTIVE_END;
388 case LEAF_pfTimeoutsSrcNode:
389 pt.timeout = PFTM_SRC_NODE;
393 return (SNMP_ERR_NOSUCHNAME);
396 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
397 syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
399 return (SNMP_ERR_GENERR);
402 val->v.integer = pt.seconds;
404 return (SNMP_ERR_NOERROR);
411 pf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
412 u_int sub, u_int __unused vindex, enum snmp_op op)
414 asn_subid_t which = val->var.subs[sub - 1];
415 unsigned char str[IFNAMSIZ];
417 if (op == SNMP_OP_SET)
418 return (SNMP_ERR_NOT_WRITEABLE);
420 if (op == SNMP_OP_GET) {
421 if (pfs_refresh() == -1)
422 return (SNMP_ERR_GENERR);
425 case LEAF_pfLogInterfaceName:
426 strlcpy(str, pfs.ifname, sizeof str);
427 return (string_get(val, str, strlen(str)));
428 case LEAF_pfLogInterfaceIp4BytesIn:
429 val->v.counter64 = pfs.bcounters[IPV4][IN];
431 case LEAF_pfLogInterfaceIp4BytesOut:
432 val->v.counter64 = pfs.bcounters[IPV4][OUT];
434 case LEAF_pfLogInterfaceIp4PktsInPass:
436 pfs.pcounters[IPV4][IN][PF_PASS];
438 case LEAF_pfLogInterfaceIp4PktsInDrop:
440 pfs.pcounters[IPV4][IN][PF_DROP];
442 case LEAF_pfLogInterfaceIp4PktsOutPass:
444 pfs.pcounters[IPV4][OUT][PF_PASS];
446 case LEAF_pfLogInterfaceIp4PktsOutDrop:
448 pfs.pcounters[IPV4][OUT][PF_DROP];
450 case LEAF_pfLogInterfaceIp6BytesIn:
451 val->v.counter64 = pfs.bcounters[IPV6][IN];
453 case LEAF_pfLogInterfaceIp6BytesOut:
454 val->v.counter64 = pfs.bcounters[IPV6][OUT];
456 case LEAF_pfLogInterfaceIp6PktsInPass:
458 pfs.pcounters[IPV6][IN][PF_PASS];
460 case LEAF_pfLogInterfaceIp6PktsInDrop:
462 pfs.pcounters[IPV6][IN][PF_DROP];
464 case LEAF_pfLogInterfaceIp6PktsOutPass:
466 pfs.pcounters[IPV6][OUT][PF_PASS];
468 case LEAF_pfLogInterfaceIp6PktsOutDrop:
470 pfs.pcounters[IPV6][OUT][PF_DROP];
474 return (SNMP_ERR_NOSUCHNAME);
477 return (SNMP_ERR_NOERROR);
484 pf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
485 u_int sub, u_int __unused vindex, enum snmp_op op)
487 asn_subid_t which = val->var.subs[sub - 1];
489 if (op == SNMP_OP_SET)
490 return (SNMP_ERR_NOT_WRITEABLE);
492 if (op == SNMP_OP_GET) {
493 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
494 if (pfi_refresh() == -1)
495 return (SNMP_ERR_GENERR);
498 case LEAF_pfInterfacesIfNumber:
499 val->v.uint32 = pfi_table_count;
503 return (SNMP_ERR_NOSUCHNAME);
506 return (SNMP_ERR_NOERROR);
513 pf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
514 u_int sub, u_int __unused vindex, enum snmp_op op)
516 asn_subid_t which = val->var.subs[sub - 1];
517 struct pfi_entry *e = NULL;
521 return (SNMP_ERR_NOT_WRITEABLE);
522 case SNMP_OP_GETNEXT:
523 if ((e = NEXT_OBJECT_INT(&pfi_table,
524 &val->var, sub)) == NULL)
525 return (SNMP_ERR_NOSUCHNAME);
526 val->var.len = sub + 1;
527 val->var.subs[sub] = e->index;
530 if (val->var.len - sub != 1)
531 return (SNMP_ERR_NOSUCHNAME);
532 if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
533 return (SNMP_ERR_NOSUCHNAME);
537 case SNMP_OP_ROLLBACK:
542 if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
546 case LEAF_pfInterfacesIfDescr:
547 return (string_get(val, e->pfi.pfik_name, -1));
548 case LEAF_pfInterfacesIfType:
549 val->v.integer = PFI_IFTYPE_INSTANCE;
551 case LEAF_pfInterfacesIfTZero:
553 (time(NULL) - e->pfi.pfik_tzero) * 100;
555 case LEAF_pfInterfacesIfRefsState:
556 val->v.uint32 = e->pfi.pfik_states;
558 case LEAF_pfInterfacesIfRefsRule:
559 val->v.uint32 = e->pfi.pfik_rules;
561 case LEAF_pfInterfacesIf4BytesInPass:
563 e->pfi.pfik_bytes[IPV4][IN][PASS];
565 case LEAF_pfInterfacesIf4BytesInBlock:
567 e->pfi.pfik_bytes[IPV4][IN][BLOCK];
569 case LEAF_pfInterfacesIf4BytesOutPass:
571 e->pfi.pfik_bytes[IPV4][OUT][PASS];
573 case LEAF_pfInterfacesIf4BytesOutBlock:
575 e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
577 case LEAF_pfInterfacesIf4PktsInPass:
579 e->pfi.pfik_packets[IPV4][IN][PASS];
581 case LEAF_pfInterfacesIf4PktsInBlock:
583 e->pfi.pfik_packets[IPV4][IN][BLOCK];
585 case LEAF_pfInterfacesIf4PktsOutPass:
587 e->pfi.pfik_packets[IPV4][OUT][PASS];
589 case LEAF_pfInterfacesIf4PktsOutBlock:
591 e->pfi.pfik_packets[IPV4][OUT][BLOCK];
593 case LEAF_pfInterfacesIf6BytesInPass:
595 e->pfi.pfik_bytes[IPV6][IN][PASS];
597 case LEAF_pfInterfacesIf6BytesInBlock:
599 e->pfi.pfik_bytes[IPV6][IN][BLOCK];
601 case LEAF_pfInterfacesIf6BytesOutPass:
603 e->pfi.pfik_bytes[IPV6][OUT][PASS];
605 case LEAF_pfInterfacesIf6BytesOutBlock:
607 e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
609 case LEAF_pfInterfacesIf6PktsInPass:
611 e->pfi.pfik_packets[IPV6][IN][PASS];
613 case LEAF_pfInterfacesIf6PktsInBlock:
615 e->pfi.pfik_packets[IPV6][IN][BLOCK];
617 case LEAF_pfInterfacesIf6PktsOutPass:
619 e->pfi.pfik_packets[IPV6][OUT][PASS];
621 case LEAF_pfInterfacesIf6PktsOutBlock:
623 e->pfi.pfik_packets[IPV6][OUT][BLOCK];
627 return (SNMP_ERR_NOSUCHNAME);
630 return (SNMP_ERR_NOERROR);
634 pf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
635 u_int sub, u_int __unused vindex, enum snmp_op op)
637 asn_subid_t which = val->var.subs[sub - 1];
639 if (op == SNMP_OP_SET)
640 return (SNMP_ERR_NOT_WRITEABLE);
642 if (op == SNMP_OP_GET) {
643 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
644 if (pft_refresh() == -1)
645 return (SNMP_ERR_GENERR);
648 case LEAF_pfTablesTblNumber:
649 val->v.uint32 = pft_table_count;
653 return (SNMP_ERR_NOSUCHNAME);
656 return (SNMP_ERR_NOERROR);
663 pf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
664 u_int sub, u_int __unused vindex, enum snmp_op op)
666 asn_subid_t which = val->var.subs[sub - 1];
667 struct pft_entry *e = NULL;
671 return (SNMP_ERR_NOT_WRITEABLE);
672 case SNMP_OP_GETNEXT:
673 if ((e = NEXT_OBJECT_INT(&pft_table,
674 &val->var, sub)) == NULL)
675 return (SNMP_ERR_NOSUCHNAME);
676 val->var.len = sub + 1;
677 val->var.subs[sub] = e->index;
680 if (val->var.len - sub != 1)
681 return (SNMP_ERR_NOSUCHNAME);
682 if ((e = pft_table_find(val->var.subs[sub])) == NULL)
683 return (SNMP_ERR_NOSUCHNAME);
687 case SNMP_OP_ROLLBACK:
692 if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
696 case LEAF_pfTablesTblDescr:
697 return (string_get(val, e->pft.pfrts_name, -1));
698 case LEAF_pfTablesTblCount:
699 val->v.integer = e->pft.pfrts_cnt;
701 case LEAF_pfTablesTblTZero:
703 (time(NULL) - e->pft.pfrts_tzero) * 100;
705 case LEAF_pfTablesTblRefsAnchor:
707 e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
709 case LEAF_pfTablesTblRefsRule:
711 e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
713 case LEAF_pfTablesTblEvalMatch:
714 val->v.counter64 = e->pft.pfrts_match;
716 case LEAF_pfTablesTblEvalNoMatch:
717 val->v.counter64 = e->pft.pfrts_nomatch;
719 case LEAF_pfTablesTblBytesInPass:
721 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
723 case LEAF_pfTablesTblBytesInBlock:
725 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
727 case LEAF_pfTablesTblBytesInXPass:
729 e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
731 case LEAF_pfTablesTblBytesOutPass:
733 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
735 case LEAF_pfTablesTblBytesOutBlock:
737 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
739 case LEAF_pfTablesTblBytesOutXPass:
741 e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
743 case LEAF_pfTablesTblPktsInPass:
745 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
747 case LEAF_pfTablesTblPktsInBlock:
749 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
751 case LEAF_pfTablesTblPktsInXPass:
753 e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
755 case LEAF_pfTablesTblPktsOutPass:
757 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
759 case LEAF_pfTablesTblPktsOutBlock:
761 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
763 case LEAF_pfTablesTblPktsOutXPass:
765 e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
769 return (SNMP_ERR_NOSUCHNAME);
772 return (SNMP_ERR_NOERROR);
776 pf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
777 u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
779 return (SNMP_ERR_GENERR);
783 pf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
784 u_int sub, u_int __unused vindex, enum snmp_op op)
786 asn_subid_t which = val->var.subs[sub - 1];
789 return (SNMP_ERR_NOERROR);
792 if (op == SNMP_OP_SET)
793 return (SNMP_ERR_NOT_WRITEABLE);
795 if (op == SNMP_OP_GET) {
796 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
797 if (pfq_refresh() == -1)
798 return (SNMP_ERR_GENERR);
801 case LEAF_pfAltqQueueNumber:
802 val->v.uint32 = pfq_table_count;
806 return (SNMP_ERR_NOSUCHNAME);
809 return (SNMP_ERR_NOERROR);
813 return (SNMP_ERR_GENERR);
817 pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
818 u_int sub, u_int __unused vindex, enum snmp_op op)
820 asn_subid_t which = val->var.subs[sub - 1];
821 struct pfq_entry *e = NULL;
824 return (SNMP_ERR_NOERROR);
829 return (SNMP_ERR_NOT_WRITEABLE);
830 case SNMP_OP_GETNEXT:
831 if ((e = NEXT_OBJECT_INT(&pfq_table,
832 &val->var, sub)) == NULL)
833 return (SNMP_ERR_NOSUCHNAME);
834 val->var.len = sub + 1;
835 val->var.subs[sub] = e->index;
838 if (val->var.len - sub != 1)
839 return (SNMP_ERR_NOSUCHNAME);
840 if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
841 return (SNMP_ERR_NOSUCHNAME);
845 case SNMP_OP_ROLLBACK:
850 if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
854 case LEAF_pfAltqQueueDescr:
855 return (string_get(val, e->altq.qname, -1));
856 case LEAF_pfAltqQueueParent:
857 return (string_get(val, e->altq.parent, -1));
858 case LEAF_pfAltqQueueScheduler:
859 val->v.integer = e->altq.scheduler;
861 case LEAF_pfAltqQueueBandwidth:
862 val->v.uint32 = e->altq.bandwidth;
864 case LEAF_pfAltqQueuePriority:
865 val->v.integer = e->altq.priority;
867 case LEAF_pfAltqQueueLimit:
868 val->v.integer = e->altq.qlimit;
872 return (SNMP_ERR_NOSUCHNAME);
875 return (SNMP_ERR_NOERROR);
878 static struct pfi_entry *
879 pfi_table_find(u_int idx)
883 TAILQ_FOREACH(e, &pfi_table, link)
889 static struct pfq_entry *
890 pfq_table_find(u_int idx)
893 TAILQ_FOREACH(e, &pfq_table, link)
899 static struct pft_entry *
900 pft_table_find(u_int idx)
904 TAILQ_FOREACH(e, &pft_table, link)
913 struct pfioc_iface io;
914 struct pfi_kif *p = NULL;
918 if (started && this_tick <= pf_tick)
921 while (!TAILQ_EMPTY(&pfi_table)) {
922 e = TAILQ_FIRST(&pfi_table);
923 TAILQ_REMOVE(&pfi_table, e, link);
927 bzero(&io, sizeof(io));
928 io.pfiio_esize = sizeof(struct pfi_kif);
931 p = reallocf(p, numifs * sizeof(struct pfi_kif));
933 syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
934 numifs, strerror(errno));
937 io.pfiio_size = numifs;
940 if (ioctl(dev, DIOCIGETIFACES, &io)) {
941 syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
946 if (numifs >= io.pfiio_size)
949 numifs = io.pfiio_size;
952 for (i = 0; i < numifs; i++) {
953 e = malloc(sizeof(struct pfi_entry));
957 memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
958 TAILQ_INSERT_TAIL(&pfi_table, e, link);
961 pfi_table_age = time(NULL);
962 pfi_table_count = numifs;
969 while (!TAILQ_EMPTY(&pfi_table)) {
970 e = TAILQ_FIRST(&pfi_table);
971 TAILQ_REMOVE(&pfi_table, e, link);
982 struct pfioc_altq pa;
984 int i, numqs, ticket;
986 if (started && this_tick <= pf_tick)
989 while (!TAILQ_EMPTY(&pfq_table)) {
990 e = TAILQ_FIRST(&pfq_table);
991 TAILQ_REMOVE(&pfq_table, e, link);
995 bzero(&pa, sizeof(pa));
997 if (ioctl(dev, DIOCGETALTQS, &pa)) {
998 syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
1006 for (i = 0; i < numqs; i++) {
1007 e = malloc(sizeof(struct pfq_entry));
1009 syslog(LOG_ERR, "pfq_refresh(): "
1017 if (ioctl(dev, DIOCGETALTQ, &pa)) {
1018 syslog(LOG_ERR, "pfq_refresh(): "
1019 "ioctl(DIOCGETALTQ): %s",
1024 if (pa.altq.qid > 0) {
1025 memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1026 e->index = pa.altq.qid;
1027 pfq_table_count = i;
1028 INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
1032 pfq_table_age = time(NULL);
1033 pf_tick = this_tick;
1038 while (!TAILQ_EMPTY(&pfq_table)) {
1039 e = TAILQ_FIRST(&pfq_table);
1040 TAILQ_REMOVE(&pfq_table, e, link);
1049 if (started && this_tick <= pf_tick)
1052 bzero(&pfs, sizeof(struct pf_status));
1054 if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1055 syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1060 pf_tick = this_tick;
1067 struct pfioc_table io;
1068 struct pfr_tstats *t = NULL;
1069 struct pft_entry *e;
1072 if (started && this_tick <= pf_tick)
1075 while (!TAILQ_EMPTY(&pft_table)) {
1076 e = TAILQ_FIRST(&pft_table);
1077 TAILQ_REMOVE(&pft_table, e, link);
1081 bzero(&io, sizeof(io));
1082 io.pfrio_esize = sizeof(struct pfr_tstats);
1085 t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1087 syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1088 numtbls, strerror(errno));
1091 io.pfrio_size = numtbls;
1092 io.pfrio_buffer = t;
1094 if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1095 syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1100 if (numtbls >= io.pfrio_size)
1103 numtbls = io.pfrio_size;
1106 for (i = 0; i < numtbls; i++) {
1107 e = malloc(sizeof(struct pft_entry));
1111 memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1112 TAILQ_INSERT_TAIL(&pft_table, e, link);
1115 pft_table_age = time(NULL);
1116 pft_table_count = numtbls;
1117 pf_tick = this_tick;
1122 while (!TAILQ_EMPTY(&pft_table)) {
1123 e = TAILQ_FIRST(&pft_table);
1124 TAILQ_REMOVE(&pft_table, e, link);
1133 * check whether altq support is enabled in kernel
1137 altq_is_enabled(int pfdev)
1139 struct pfioc_altq pa;
1142 if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1143 if (errno == ENODEV) {
1144 syslog(LOG_INFO, "No ALTQ support in kernel\n"
1145 "ALTQ related functions disabled\n");
1148 syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1156 * Implement the bsnmpd module interface
1159 pf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1163 if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1164 syslog(LOG_ERR, "pf_init(): open(): %s\n",
1169 if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1170 syslog(LOG_ERR, "pf_init(): altq test failed");
1174 /* Prepare internal state */
1175 TAILQ_INIT(&pfi_table);
1176 TAILQ_INIT(&pfq_table);
1177 TAILQ_INIT(&pft_table);
1195 struct pfi_entry *i1, *i2;
1196 struct pfq_entry *q1, *q2;
1197 struct pft_entry *t1, *t2;
1199 /* Empty the list of interfaces */
1200 i1 = TAILQ_FIRST(&pfi_table);
1201 while (i1 != NULL) {
1202 i2 = TAILQ_NEXT(i1, link);
1207 /* List of queues */
1208 q1 = TAILQ_FIRST(&pfq_table);
1209 while (q1 != NULL) {
1210 q2 = TAILQ_NEXT(q1, link);
1215 /* And the list of tables */
1216 t1 = TAILQ_FIRST(&pft_table);
1217 while (t1 != NULL) {
1218 t2 = TAILQ_NEXT(t1, link);
1236 syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1237 (intmax_t)pfi_table_age);
1238 syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1241 syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1242 (intmax_t)pfq_table_age);
1243 syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1246 syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1247 (intmax_t)pft_table_age);
1249 syslog(LOG_ERR, "Dump: pft_table_count = %d",
1253 const struct snmp_module config = {
1254 .comment = "This module implements a MIB for the pf packet filter.",
1259 .tree_size = pf_CTREE_SIZE,