GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/pfctl/pfctl_queue.c Lines: 0 88 0.0 %
Date: 2016-12-06 Branches: 0 68 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: pfctl_queue.c,v 1.2 2014/04/19 14:22:32 henning Exp $ */
2
3
/*
4
 * Copyright (c) 2003 - 2013 Henning Brauer <henning@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/ioctl.h>
21
#include <sys/socket.h>
22
23
#include <net/if.h>
24
#include <netinet/in.h>
25
#include <net/pfvar.h>
26
#include <arpa/inet.h>
27
28
#include <err.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
34
#include <net/hfsc.h>
35
36
#include "pfctl.h"
37
#include "pfctl_parser.h"
38
39
#define AVGN_MAX	8
40
#define STAT_INTERVAL	5
41
42
struct queue_stats {
43
	struct hfsc_class_stats	 data;
44
	int			 avgn;
45
	double			 avg_bytes;
46
	double			 avg_packets;
47
	u_int64_t		 prev_bytes;
48
	u_int64_t		 prev_packets;
49
};
50
51
struct pfctl_queue_node {
52
	TAILQ_ENTRY(pfctl_queue_node)	entries;
53
	struct pf_queuespec		qs;
54
	struct queue_stats		qstats;
55
};
56
TAILQ_HEAD(qnodes, pfctl_queue_node) qnodes = TAILQ_HEAD_INITIALIZER(qnodes);
57
58
int			 pfctl_update_qstats(int);
59
void			 pfctl_insert_queue_node(const struct pf_queuespec,
60
			    const struct queue_stats);
61
struct pfctl_queue_node	*pfctl_find_queue_node(const char *, const char *);
62
void			 pfctl_print_queue_node(int, struct pfctl_queue_node *,
63
			    int);
64
void			 print_qstats(struct queue_stats);
65
void			 pfctl_free_queue_node(struct pfctl_queue_node *);
66
void			 pfctl_print_queue_nodestat(int,
67
			    const struct pfctl_queue_node *);
68
void			 update_avg(struct queue_stats *);
69
char			*rate2str(double);
70
71
int
72
pfctl_show_queues(int dev, const char *iface, int opts, int verbose2)
73
{
74
	struct pfctl_queue_node	*node;
75
	int			 nodes, dotitle = (opts & PF_OPT_SHOWALL);
76
77
78
	if ((nodes = pfctl_update_qstats(dev)) <= 0)
79
		return (nodes);
80
81
	TAILQ_FOREACH(node, &qnodes, entries) {
82
		if (iface != NULL && strcmp(node->qs.ifname, iface))
83
			continue;
84
		if (dotitle) {
85
			pfctl_print_title("QUEUES:");
86
			dotitle = 0;
87
		}
88
		pfctl_print_queue_node(dev, node, opts);
89
	}
90
91
	while (verbose2 && nodes > 0) {
92
		printf("\n");
93
		fflush(stdout);
94
		sleep(STAT_INTERVAL);
95
		if ((nodes = pfctl_update_qstats(dev)) == -1)
96
			return (-1);
97
		TAILQ_FOREACH(node, &qnodes, entries) {
98
			if (iface != NULL && strcmp(node->qs.ifname, iface))
99
				continue;
100
			pfctl_print_queue_node(dev, node, opts);
101
		}
102
	}
103
	while ((node = TAILQ_FIRST(&qnodes)) != NULL)
104
		TAILQ_REMOVE(&qnodes, node, entries);
105
	return (0);
106
}
107
108
int
109
pfctl_update_qstats(int dev)
110
{
111
	struct pfctl_queue_node	*node;
112
	struct pfioc_queue	 pq;
113
	struct pfioc_qstats	 pqs;
114
	u_int32_t		 mnr, nr;
115
	struct queue_stats	 qstats;
116
	static u_int32_t	 last_ticket;
117
118
	memset(&pq, 0, sizeof(pq));
119
	memset(&pqs, 0, sizeof(pqs));
120
	memset(&qstats, 0, sizeof(qstats));
121
	if (ioctl(dev, DIOCGETQUEUES, &pq)) {
122
		warn("DIOCGETQUEUES");
123
		return (-1);
124
	}
125
126
	/* if a new set is found, start over */
127
	if (pq.ticket != last_ticket)
128
		while ((node = TAILQ_FIRST(&qnodes)) != NULL)
129
			TAILQ_REMOVE(&qnodes, node, entries);
130
	last_ticket = pq.ticket;
131
132
	mnr = pq.nr;
133
	for (nr = 0; nr < mnr; ++nr) {
134
		pqs.nr = nr;
135
		pqs.ticket = pq.ticket;
136
		pqs.buf = &qstats.data;
137
		pqs.nbytes = sizeof(qstats.data);
138
		if (ioctl(dev, DIOCGETQSTATS, &pqs)) {
139
			warn("DIOCGETQSTATS");
140
			return (-1);
141
		}
142
//		if (pqs.queue.qname[0] != '_') {
143
//			if (pqs.queue.parent[0] && pqs.queue.parent[0] == '_')
144
//				pqs.queue.parent[0] = 0;
145
			if ((node = pfctl_find_queue_node(pqs.queue.qname,
146
			    pqs.queue.ifname)) != NULL) {
147
				memcpy(&node->qstats.data, &qstats.data,
148
				    sizeof(qstats.data));
149
				update_avg(&node->qstats);
150
			} else {
151
				pfctl_insert_queue_node(pqs.queue, qstats);
152
			}
153
//		}
154
	}
155
	return (mnr);
156
}
157
158
void
159
pfctl_insert_queue_node(const struct pf_queuespec qs,
160
    const struct queue_stats qstats)
161
{
162
	struct pfctl_queue_node	*node;
163
164
	node = calloc(1, sizeof(struct pfctl_queue_node));
165
	if (node == NULL)
166
		err(1, "pfctl_insert_queue_node: calloc");
167
	memcpy(&node->qs, &qs, sizeof(qs));
168
	memcpy(&node->qstats, &qstats, sizeof(qstats));
169
	TAILQ_INSERT_TAIL(&qnodes, node, entries);
170
	update_avg(&node->qstats);
171
}
172
173
struct pfctl_queue_node *
174
pfctl_find_queue_node(const char *qname, const char *ifname)
175
{
176
	struct pfctl_queue_node	*node;
177
178
	TAILQ_FOREACH(node, &qnodes, entries)
179
		if (!strcmp(node->qs.qname, qname)
180
		    && !(strcmp(node->qs.ifname, ifname)))
181
			return (node);
182
	return (NULL);
183
}
184
185
void
186
pfctl_print_queue_node(int dev, struct pfctl_queue_node *node, int opts)
187
{
188
	if (node == NULL)
189
		return;
190
191
	print_queuespec(&node->qs);
192
	if (opts & PF_OPT_VERBOSE)
193
		pfctl_print_queue_nodestat(dev, node);
194
195
	if (opts & PF_OPT_DEBUG)
196
		printf("  [ qid=%u parent_qid=%u ifname=%s]\n",
197
		    node->qs.qid, node->qs.parent_qid, node->qs.ifname);
198
}
199
200
void
201
pfctl_print_queue_nodestat(int dev, const struct pfctl_queue_node *node)
202
{
203
	printf("  [ pkts: %10llu  bytes: %10llu  "
204
	    "dropped pkts: %6llu bytes: %6llu ]\n",
205
	    (unsigned long long)node->qstats.data.xmit_cnt.packets,
206
	    (unsigned long long)node->qstats.data.xmit_cnt.bytes,
207
	    (unsigned long long)node->qstats.data.drop_cnt.packets,
208
	    (unsigned long long)node->qstats.data.drop_cnt.bytes);
209
	printf("  [ qlength: %3d/%3d ]\n", node->qstats.data.qlength,
210
	    node->qstats.data.qlimit);
211
212
	if (node->qstats.avgn < 2)
213
		return;
214
215
	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
216
	    node->qstats.avg_packets / STAT_INTERVAL,
217
	    rate2str((8 * node->qstats.avg_bytes) / STAT_INTERVAL));
218
}
219
220
void
221
update_avg(struct queue_stats *s)
222
{
223
	if (s->avgn > 0) {
224
		if (s->data.xmit_cnt.bytes >= s->prev_bytes)
225
			s->avg_bytes = ((s->avg_bytes * (s->avgn - 1)) +
226
			    (s->data.xmit_cnt.bytes - s->prev_bytes)) /
227
			    s->avgn;
228
		if (s->data.xmit_cnt.packets >= s->prev_packets)
229
			s->avg_packets = ((s->avg_packets * (s->avgn - 1)) +
230
			    (s->data.xmit_cnt.packets - s->prev_packets)) /
231
			    s->avgn;
232
	}
233
234
	s->prev_bytes = s->data.xmit_cnt.bytes;
235
	s->prev_packets = s->data.xmit_cnt.packets;
236
	if (s->avgn < AVGN_MAX)
237
		s->avgn++;
238
}
239
240
#define	R2S_BUFS	8
241
#define	RATESTR_MAX	16
242
243
char *
244
rate2str(double rate)
245
{
246
	char		*buf;
247
	static char	 r2sbuf[R2S_BUFS][RATESTR_MAX];  /* ring bufer */
248
	static int	 idx = 0;
249
	int		 i;
250
	static const char unit[] = " KMG";
251
252
	buf = r2sbuf[idx++];
253
	if (idx == R2S_BUFS)
254
		idx = 0;
255
256
	for (i = 0; rate >= 1000 && i <= 3; i++)
257
		rate /= 1000;
258
259
	if ((int)(rate * 100) % 100)
260
		snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]);
261
	else
262
		snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]);
263
264
	return (buf);
265
}