|
@@ -0,0 +1,235 @@
|
|
|
+/* $Id: sm_pfq.c,v 1.1 2005/03/20 16:17:22 dijkstra Exp $ */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Copyright (c) 2005 J. Martin Petersen
|
|
|
+ * All rights reserved.
|
|
|
+ *
|
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
|
+ * modification, are permitted provided that the following conditions
|
|
|
+ * are met:
|
|
|
+ *
|
|
|
+ * - Redistributions of source code must retain the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
|
+ * - Redistributions in binary form must reproduce the above
|
|
|
+ * copyright notice, this list of conditions and the following
|
|
|
+ * disclaimer in the documentation and/or other materials provided
|
|
|
+ * with the distribution.
|
|
|
+ *
|
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
+ * POSSIBILITY OF SUCH DAMAGE.
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Get current altq statistics from pf and return them in symon_buf as
|
|
|
+ * sent_bytes : sent_packets : drop_bytes : drop_packets
|
|
|
+ *
|
|
|
+ * Non re-entrant code: gets_pfq messes with the globals without locking.
|
|
|
+ */
|
|
|
+
|
|
|
+#include "conf.h"
|
|
|
+
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/socket.h>
|
|
|
+#include <sys/ioctl.h>
|
|
|
+#include <net/if.h>
|
|
|
+#include <err.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+
|
|
|
+#ifdef HAS_PFVAR_H
|
|
|
+#include <net/pfvar.h>
|
|
|
+#include <altq/altq.h>
|
|
|
+#include <altq/altq_cbq.h>
|
|
|
+#include <altq/altq_priq.h>
|
|
|
+#include <altq/altq_hfsc.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+#include <errno.h>
|
|
|
+#include <string.h>
|
|
|
+#include <fcntl.h>
|
|
|
+
|
|
|
+#include "error.h"
|
|
|
+#include "symon.h"
|
|
|
+#include "xmalloc.h"
|
|
|
+
|
|
|
+#ifndef HAS_PFVAR_H
|
|
|
+void
|
|
|
+privinit_pfq()
|
|
|
+{
|
|
|
+ fatal("pf support not available");
|
|
|
+}
|
|
|
+void
|
|
|
+init_pfq(char *s)
|
|
|
+{
|
|
|
+ fatal("pf support not available");
|
|
|
+}
|
|
|
+void
|
|
|
+gets_pfq()
|
|
|
+{
|
|
|
+ fatal("pf support not available");
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+get_pfq(char *b, int l, char *s)
|
|
|
+{
|
|
|
+ fatal("pf support not available");
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+union class_stats {
|
|
|
+ class_stats_t cbq;
|
|
|
+ struct priq_classstats priq;
|
|
|
+ struct hfsc_classstats hfsc;
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * We don't reuse the data structures from altq/altq_{cbq|hfsc|priq}.h as they
|
|
|
+ * are overly complex. For now we only grab the interesting stuff.
|
|
|
+ */
|
|
|
+
|
|
|
+struct altq_stats {
|
|
|
+ char qname[PF_QNAME_SIZE];
|
|
|
+ u_int64_t sent_bytes;
|
|
|
+ u_int64_t sent_packets;
|
|
|
+ u_int64_t drop_bytes;
|
|
|
+ u_int64_t drop_packets;
|
|
|
+};
|
|
|
+
|
|
|
+static struct altq_stats *pfq_stats = NULL;
|
|
|
+static int pfq_numstats = 0;
|
|
|
+int pfq_dev = -1;
|
|
|
+
|
|
|
+void
|
|
|
+privinit_pfq()
|
|
|
+{
|
|
|
+ if ((pfq_dev = open("/dev/pf", O_RDONLY)) == -1) {
|
|
|
+ warning("pfq: could not open \"/dev/pf\", %.200s", strerror(errno));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+init_pfq(char *s)
|
|
|
+{
|
|
|
+ if (pfq_dev == -1) {
|
|
|
+ privinit_pfq();
|
|
|
+ }
|
|
|
+
|
|
|
+ info("started module pfq(%.200s)",s);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+gets_pfq()
|
|
|
+{
|
|
|
+ struct pfioc_altq qs;
|
|
|
+ struct pfioc_qstats stats;
|
|
|
+ union class_stats q;
|
|
|
+ unsigned int nqs;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ bzero(&qs, sizeof(qs));
|
|
|
+ bzero(&stats, sizeof(stats));
|
|
|
+ bzero(&q, sizeof(q));
|
|
|
+
|
|
|
+ if (ioctl(pfq_dev, DIOCGETALTQS, &qs)) {
|
|
|
+ fatal("pfq: DIOCGETALTQS failed");
|
|
|
+ }
|
|
|
+ nqs = qs.nr;
|
|
|
+
|
|
|
+ /* Allocate memory for info for the nqs queues */
|
|
|
+ if (nqs > pfq_numstats) {
|
|
|
+ if (pfq_stats) {
|
|
|
+ xfree(pfq_stats);
|
|
|
+ }
|
|
|
+
|
|
|
+ pfq_stats = xmalloc(nqs * sizeof(struct altq_stats));
|
|
|
+ pfq_numstats = nqs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Loop through the queues, copy info */
|
|
|
+ for (i = 0; i < nqs; i++) {
|
|
|
+ qs.nr = i;
|
|
|
+ if (ioctl(pfq_dev, DIOCGETALTQ, &qs)) {
|
|
|
+ fatal("pfq: DIOCGETALTQ failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* only process the non-empty queues */
|
|
|
+ if (qs.altq.qid > 0) {
|
|
|
+ stats.nr = qs.nr;
|
|
|
+ stats.ticket = qs.ticket;
|
|
|
+ stats.buf = &q;
|
|
|
+ stats.nbytes = sizeof(q);
|
|
|
+
|
|
|
+ if (ioctl(pfq_dev, DIOCGETQSTATS, &stats)) {
|
|
|
+ fatal("pfq: DIOCGETQSTATS failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* We're now ready to copy the data we want. */
|
|
|
+ strncpy(pfq_stats[i].qname, qs.altq.qname, PF_QNAME_SIZE);
|
|
|
+
|
|
|
+ switch (qs.altq.scheduler) {
|
|
|
+ case ALTQT_CBQ:
|
|
|
+ pfq_stats[i].sent_bytes = q.cbq.xmit_cnt.bytes;
|
|
|
+ pfq_stats[i].sent_packets = q.cbq.xmit_cnt.packets;
|
|
|
+ pfq_stats[i].drop_bytes = q.cbq.drop_cnt.bytes;
|
|
|
+ pfq_stats[i].drop_packets = q.cbq.drop_cnt.packets;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ALTQT_PRIQ:
|
|
|
+ pfq_stats[i].sent_bytes = q.priq.xmitcnt.bytes;
|
|
|
+ pfq_stats[i].sent_packets = q.priq.xmitcnt.packets;
|
|
|
+ pfq_stats[i].drop_bytes = q.priq.dropcnt.bytes;
|
|
|
+ pfq_stats[i].drop_packets = q.priq.dropcnt.packets;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ALTQT_HFSC:
|
|
|
+ pfq_stats[i].sent_bytes = q.hfsc.xmit_cnt.bytes;
|
|
|
+ pfq_stats[i].sent_packets = q.hfsc.xmit_cnt.packets;
|
|
|
+ pfq_stats[i].drop_bytes = q.hfsc.drop_cnt.bytes;
|
|
|
+ pfq_stats[i].drop_packets = q.hfsc.drop_cnt.packets;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ warning("pfq: unknown altq scheduler type encountered");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Make sure the lookup in get_pfq fails immediately whenever
|
|
|
+ * there's no queue in the slot. We do this by nul'ing the name */
|
|
|
+ pfq_stats[i].qname[0] = '\0';
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+get_pfq(char *symon_buf, int maxlen, char *queue)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < pfq_numstats; i++) {
|
|
|
+ if (strncmp(pfq_stats[i].qname, queue, PF_QNAME_SIZE) == 0) {
|
|
|
+ return snpack(symon_buf, maxlen, queue, MT_PFQ,
|
|
|
+ pfq_stats[i].sent_bytes,
|
|
|
+ pfq_stats[i].sent_packets,
|
|
|
+ pfq_stats[i].drop_bytes,
|
|
|
+ pfq_stats[i].drop_packets
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|